mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	Replace samples for C language
This commit is contained in:
		
							
								
								
									
										45
									
								
								samples/C/array.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								samples/C/array.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | #include <array.h> | ||||||
|  |  | ||||||
|  | unsigned __bump_up(unsigned n) { | ||||||
|  |     unsigned base = 1; | ||||||
|  |     --n; | ||||||
|  |     while (base < sizeof n * 8) { | ||||||
|  |         n |= n >> base; | ||||||
|  |         base *= 2; | ||||||
|  |     } | ||||||
|  |     ++n; | ||||||
|  |     n += (n == 0); | ||||||
|  |     return n; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void *__array_alloc(size_t size, unsigned length) { | ||||||
|  |     unsigned allocated = __bump_up(length); | ||||||
|  |     struct __array_header *head = malloc(sizeof *head + allocated * size); | ||||||
|  |     assert(head); | ||||||
|  |     head->length = length; | ||||||
|  |     head->allocated = allocated; | ||||||
|  |     return (void *) (head + 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void __array_resize(void **array, size_t size, int difference) { | ||||||
|  |     if (difference == 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     struct __array_header *head = __header(*array); | ||||||
|  |     head->length += difference; | ||||||
|  |     if (head->length >= head->allocated) { | ||||||
|  |         head->allocated = __bump_up(head->length); | ||||||
|  |         head = realloc(head, sizeof *head + head->allocated * size); | ||||||
|  |         assert(head); | ||||||
|  |         *array = head + 1; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int __array_search(void *array, void *elem, size_t size) { | ||||||
|  |     for (unsigned i = 0; i < alength(array) * size; i += size) { | ||||||
|  |         if (memcmp((char *)array + i, elem, size) == 0) { | ||||||
|  |             return 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								samples/C/array.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								samples/C/array.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | #ifndef ARRAY_H | ||||||
|  | #define ARRAY_H value | ||||||
|  |  | ||||||
|  | #include <assert.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | #define array(type, name, initial_length) \ | ||||||
|  |     type *name = __array_alloc(sizeof(type), initial_length) | ||||||
|  |  | ||||||
|  | #define aforeach(it, array) \ | ||||||
|  |     for (unsigned it = 0; \ | ||||||
|  |             it < alength(array); \ | ||||||
|  |             ++it) | ||||||
|  |  | ||||||
|  | #define __header(array) \ | ||||||
|  |     ((struct __array_header *) array - 1) | ||||||
|  |  | ||||||
|  | #define alength(array) \ | ||||||
|  |     (__header(array)->length) | ||||||
|  |  | ||||||
|  | #define afree(array) \ | ||||||
|  |     free(__header(array)) | ||||||
|  |  | ||||||
|  | #define apush(array, elem) \ | ||||||
|  |     __array_resize((void **) &array, sizeof *array, 1); \ | ||||||
|  |     array[alength(array)-1] = elem | ||||||
|  |  | ||||||
|  | #define apop(array) \ | ||||||
|  |     aremove(array, (alength(array) - 1)) | ||||||
|  |  | ||||||
|  | #define aremove(array, index) \ | ||||||
|  |     assert(alength(array) > index); \ | ||||||
|  |     memmove(array + index, array + index + 1, sizeof *array * (alength(array) - index - 1)); \ | ||||||
|  |     __array_resize((void **) &array, sizeof *array, -1) | ||||||
|  |  | ||||||
|  | #define ainsert(array, index, elem) \ | ||||||
|  |     __array_resize((void **) &array, sizeof *array, index >= alength(array) ? index - alength(array) + 1 : 1); \ | ||||||
|  |     memmove(array + index + 1, array + index, sizeof *array * (alength(array) - index - 1)); \ | ||||||
|  |     array[index] = elem | ||||||
|  |  | ||||||
|  | #define acontains(array, elem) \ | ||||||
|  |     __array_search(array, &elem, sizeof elem) | ||||||
|  |  | ||||||
|  | #define __arrayallocated(array) \ | ||||||
|  |     (__header(array)->allocated) | ||||||
|  |  | ||||||
|  | struct __array_header { | ||||||
|  |     unsigned length; | ||||||
|  |     unsigned allocated; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | unsigned __bump_up(unsigned n); | ||||||
|  | void *__array_alloc(size_t size, unsigned length); | ||||||
|  | void __array_resize(void **array, size_t size, int difference); | ||||||
|  | int __array_search(void *array, void *elem, size_t size); | ||||||
|  |  | ||||||
|  | #endif /* ifndef ARRAY_H */ | ||||||
| @@ -1,99 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Copyright (C) 2009-2012 the libgit2 contributors |  | ||||||
|  * |  | ||||||
|  * This file is part of libgit2, distributed under the GNU GPL v2 with |  | ||||||
|  * a Linking Exception. For full terms see the included COPYING file. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "common.h" |  | ||||||
| #include "repository.h" |  | ||||||
| #include "commit.h" |  | ||||||
| #include "thread-utils.h" |  | ||||||
| #include "util.h" |  | ||||||
| #include "cache.h" |  | ||||||
|  |  | ||||||
| int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr) |  | ||||||
| { |  | ||||||
| 	if (size < 8) |  | ||||||
| 		size = 8; |  | ||||||
| 	size = git__size_t_powerof2(size); |  | ||||||
|  |  | ||||||
| 	cache->size_mask = size - 1; |  | ||||||
| 	cache->lru_count = 0; |  | ||||||
| 	cache->free_obj = free_ptr; |  | ||||||
|  |  | ||||||
| 	git_mutex_init(&cache->lock); |  | ||||||
|  |  | ||||||
| 	cache->nodes = git__malloc(size * sizeof(git_cached_obj *)); |  | ||||||
| 	GITERR_CHECK_ALLOC(cache->nodes); |  | ||||||
|  |  | ||||||
| 	memset(cache->nodes, 0x0, size * sizeof(git_cached_obj *)); |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void git_cache_free(git_cache *cache) |  | ||||||
| { |  | ||||||
| 	size_t i; |  | ||||||
|  |  | ||||||
| 	for (i = 0; i < (cache->size_mask + 1); ++i) { |  | ||||||
| 		if (cache->nodes[i] != NULL) |  | ||||||
| 			git_cached_obj_decref(cache->nodes[i], cache->free_obj); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	git__free(cache->nodes); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void *git_cache_get(git_cache *cache, const git_oid *oid) |  | ||||||
| { |  | ||||||
| 	uint32_t hash; |  | ||||||
| 	git_cached_obj *node = NULL, *result = NULL; |  | ||||||
|  |  | ||||||
| 	memcpy(&hash, oid->id, sizeof(hash)); |  | ||||||
|  |  | ||||||
| 	git_mutex_lock(&cache->lock); |  | ||||||
| 	{ |  | ||||||
| 		node = cache->nodes[hash & cache->size_mask]; |  | ||||||
|  |  | ||||||
| 		if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) { |  | ||||||
| 			git_cached_obj_incref(node); |  | ||||||
| 			result = node; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	git_mutex_unlock(&cache->lock); |  | ||||||
|  |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void *git_cache_try_store(git_cache *cache, void *_entry) |  | ||||||
| { |  | ||||||
| 	git_cached_obj *entry = _entry; |  | ||||||
| 	uint32_t hash; |  | ||||||
|  |  | ||||||
| 	memcpy(&hash, &entry->oid, sizeof(uint32_t)); |  | ||||||
|  |  | ||||||
| 	/* increase the refcount on this object, because |  | ||||||
| 	 * the cache now owns it */ |  | ||||||
| 	git_cached_obj_incref(entry); |  | ||||||
|  |  | ||||||
| 	git_mutex_lock(&cache->lock); |  | ||||||
| 	{ |  | ||||||
| 		git_cached_obj *node = cache->nodes[hash & cache->size_mask]; |  | ||||||
|  |  | ||||||
| 		if (node == NULL) { |  | ||||||
| 			cache->nodes[hash & cache->size_mask] = entry; |  | ||||||
| 		} else if (git_oid_cmp(&node->oid, &entry->oid) == 0) { |  | ||||||
| 			git_cached_obj_decref(entry, cache->free_obj); |  | ||||||
| 			entry = node; |  | ||||||
| 		} else { |  | ||||||
| 			git_cached_obj_decref(node, cache->free_obj); |  | ||||||
| 			cache->nodes[hash & cache->size_mask] = entry; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	git_mutex_unlock(&cache->lock); |  | ||||||
|  |  | ||||||
| 	/* increase the refcount again, because we are |  | ||||||
| 	 * returning it to the user */ |  | ||||||
| 	git_cached_obj_incref(entry); |  | ||||||
|  |  | ||||||
| 	return entry; |  | ||||||
| } |  | ||||||
							
								
								
									
										725
									
								
								samples/C/cpu.c
									
									
									
									
									
								
							
							
						
						
									
										725
									
								
								samples/C/cpu.c
									
									
									
									
									
								
							| @@ -1,725 +0,0 @@ | |||||||
| /* CPU control. |  | ||||||
|  * (C) 2001, 2002, 2003, 2004 Rusty Russell |  | ||||||
|  * |  | ||||||
|  * This code is licenced under the GPL. |  | ||||||
|  */ |  | ||||||
| #include <linux/proc_fs.h> |  | ||||||
| #include <linux/smp.h> |  | ||||||
| #include <linux/init.h> |  | ||||||
| #include <linux/notifier.h> |  | ||||||
| #include <linux/sched.h> |  | ||||||
| #include <linux/unistd.h> |  | ||||||
| #include <linux/cpu.h> |  | ||||||
| #include <linux/oom.h> |  | ||||||
| #include <linux/rcupdate.h> |  | ||||||
| #include <linux/export.h> |  | ||||||
| #include <linux/bug.h> |  | ||||||
| #include <linux/kthread.h> |  | ||||||
| #include <linux/stop_machine.h> |  | ||||||
| #include <linux/mutex.h> |  | ||||||
| #include <linux/gfp.h> |  | ||||||
| #include <linux/suspend.h> |  | ||||||
|  |  | ||||||
| #include "smpboot.h" |  | ||||||
|  |  | ||||||
| #ifdef CONFIG_SMP |  | ||||||
| /* Serializes the updates to cpu_online_mask, cpu_present_mask */ |  | ||||||
| static DEFINE_MUTEX(cpu_add_remove_lock); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * The following two API's must be used when attempting |  | ||||||
|  * to serialize the updates to cpu_online_mask, cpu_present_mask. |  | ||||||
|  */ |  | ||||||
| void cpu_maps_update_begin(void) |  | ||||||
| { |  | ||||||
| 	mutex_lock(&cpu_add_remove_lock); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void cpu_maps_update_done(void) |  | ||||||
| { |  | ||||||
| 	mutex_unlock(&cpu_add_remove_lock); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static RAW_NOTIFIER_HEAD(cpu_chain); |  | ||||||
|  |  | ||||||
| /* If set, cpu_up and cpu_down will return -EBUSY and do nothing. |  | ||||||
|  * Should always be manipulated under cpu_add_remove_lock |  | ||||||
|  */ |  | ||||||
| static int cpu_hotplug_disabled; |  | ||||||
|  |  | ||||||
| #ifdef CONFIG_HOTPLUG_CPU |  | ||||||
|  |  | ||||||
| static struct { |  | ||||||
| 	struct task_struct *active_writer; |  | ||||||
| 	struct mutex lock; /* Synchronizes accesses to refcount, */ |  | ||||||
| 	/* |  | ||||||
| 	 * Also blocks the new readers during |  | ||||||
| 	 * an ongoing cpu hotplug operation. |  | ||||||
| 	 */ |  | ||||||
| 	int refcount; |  | ||||||
| } cpu_hotplug = { |  | ||||||
| 	.active_writer = NULL, |  | ||||||
| 	.lock = __MUTEX_INITIALIZER(cpu_hotplug.lock), |  | ||||||
| 	.refcount = 0, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| void get_online_cpus(void) |  | ||||||
| { |  | ||||||
| 	might_sleep(); |  | ||||||
| 	if (cpu_hotplug.active_writer == current) |  | ||||||
| 		return; |  | ||||||
| 	mutex_lock(&cpu_hotplug.lock); |  | ||||||
| 	cpu_hotplug.refcount++; |  | ||||||
| 	mutex_unlock(&cpu_hotplug.lock); |  | ||||||
|  |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(get_online_cpus); |  | ||||||
|  |  | ||||||
| void put_online_cpus(void) |  | ||||||
| { |  | ||||||
| 	if (cpu_hotplug.active_writer == current) |  | ||||||
| 		return; |  | ||||||
| 	mutex_lock(&cpu_hotplug.lock); |  | ||||||
| 	if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer)) |  | ||||||
| 		wake_up_process(cpu_hotplug.active_writer); |  | ||||||
| 	mutex_unlock(&cpu_hotplug.lock); |  | ||||||
|  |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(put_online_cpus); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * This ensures that the hotplug operation can begin only when the |  | ||||||
|  * refcount goes to zero. |  | ||||||
|  * |  | ||||||
|  * Note that during a cpu-hotplug operation, the new readers, if any, |  | ||||||
|  * will be blocked by the cpu_hotplug.lock |  | ||||||
|  * |  | ||||||
|  * Since cpu_hotplug_begin() is always called after invoking |  | ||||||
|  * cpu_maps_update_begin(), we can be sure that only one writer is active. |  | ||||||
|  * |  | ||||||
|  * Note that theoretically, there is a possibility of a livelock: |  | ||||||
|  * - Refcount goes to zero, last reader wakes up the sleeping |  | ||||||
|  *   writer. |  | ||||||
|  * - Last reader unlocks the cpu_hotplug.lock. |  | ||||||
|  * - A new reader arrives at this moment, bumps up the refcount. |  | ||||||
|  * - The writer acquires the cpu_hotplug.lock finds the refcount |  | ||||||
|  *   non zero and goes to sleep again. |  | ||||||
|  * |  | ||||||
|  * However, this is very difficult to achieve in practice since |  | ||||||
|  * get_online_cpus() not an api which is called all that often. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| static void cpu_hotplug_begin(void) |  | ||||||
| { |  | ||||||
| 	cpu_hotplug.active_writer = current; |  | ||||||
|  |  | ||||||
| 	for (;;) { |  | ||||||
| 		mutex_lock(&cpu_hotplug.lock); |  | ||||||
| 		if (likely(!cpu_hotplug.refcount)) |  | ||||||
| 			break; |  | ||||||
| 		__set_current_state(TASK_UNINTERRUPTIBLE); |  | ||||||
| 		mutex_unlock(&cpu_hotplug.lock); |  | ||||||
| 		schedule(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void cpu_hotplug_done(void) |  | ||||||
| { |  | ||||||
| 	cpu_hotplug.active_writer = NULL; |  | ||||||
| 	mutex_unlock(&cpu_hotplug.lock); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #else /* #if CONFIG_HOTPLUG_CPU */ |  | ||||||
| static void cpu_hotplug_begin(void) {} |  | ||||||
| static void cpu_hotplug_done(void) {} |  | ||||||
| #endif	/* #else #if CONFIG_HOTPLUG_CPU */ |  | ||||||
|  |  | ||||||
| /* Need to know about CPUs going up/down? */ |  | ||||||
| int __ref register_cpu_notifier(struct notifier_block *nb) |  | ||||||
| { |  | ||||||
| 	int ret; |  | ||||||
| 	cpu_maps_update_begin(); |  | ||||||
| 	ret = raw_notifier_chain_register(&cpu_chain, nb); |  | ||||||
| 	cpu_maps_update_done(); |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int __cpu_notify(unsigned long val, void *v, int nr_to_call, |  | ||||||
| 			int *nr_calls) |  | ||||||
| { |  | ||||||
| 	int ret; |  | ||||||
|  |  | ||||||
| 	ret = __raw_notifier_call_chain(&cpu_chain, val, v, nr_to_call, |  | ||||||
| 					nr_calls); |  | ||||||
|  |  | ||||||
| 	return notifier_to_errno(ret); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int cpu_notify(unsigned long val, void *v) |  | ||||||
| { |  | ||||||
| 	return __cpu_notify(val, v, -1, NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #ifdef CONFIG_HOTPLUG_CPU |  | ||||||
|  |  | ||||||
| static void cpu_notify_nofail(unsigned long val, void *v) |  | ||||||
| { |  | ||||||
| 	BUG_ON(cpu_notify(val, v)); |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(register_cpu_notifier); |  | ||||||
|  |  | ||||||
| void __ref unregister_cpu_notifier(struct notifier_block *nb) |  | ||||||
| { |  | ||||||
| 	cpu_maps_update_begin(); |  | ||||||
| 	raw_notifier_chain_unregister(&cpu_chain, nb); |  | ||||||
| 	cpu_maps_update_done(); |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(unregister_cpu_notifier); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU |  | ||||||
|  * @cpu: a CPU id |  | ||||||
|  * |  | ||||||
|  * This function walks all processes, finds a valid mm struct for each one and |  | ||||||
|  * then clears a corresponding bit in mm's cpumask.  While this all sounds |  | ||||||
|  * trivial, there are various non-obvious corner cases, which this function |  | ||||||
|  * tries to solve in a safe manner. |  | ||||||
|  * |  | ||||||
|  * Also note that the function uses a somewhat relaxed locking scheme, so it may |  | ||||||
|  * be called only for an already offlined CPU. |  | ||||||
|  */ |  | ||||||
| void clear_tasks_mm_cpumask(int cpu) |  | ||||||
| { |  | ||||||
| 	struct task_struct *p; |  | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	 * This function is called after the cpu is taken down and marked |  | ||||||
| 	 * offline, so its not like new tasks will ever get this cpu set in |  | ||||||
| 	 * their mm mask. -- Peter Zijlstra |  | ||||||
| 	 * Thus, we may use rcu_read_lock() here, instead of grabbing |  | ||||||
| 	 * full-fledged tasklist_lock. |  | ||||||
| 	 */ |  | ||||||
| 	WARN_ON(cpu_online(cpu)); |  | ||||||
| 	rcu_read_lock(); |  | ||||||
| 	for_each_process(p) { |  | ||||||
| 		struct task_struct *t; |  | ||||||
|  |  | ||||||
| 		/* |  | ||||||
| 		 * Main thread might exit, but other threads may still have |  | ||||||
| 		 * a valid mm. Find one. |  | ||||||
| 		 */ |  | ||||||
| 		t = find_lock_task_mm(p); |  | ||||||
| 		if (!t) |  | ||||||
| 			continue; |  | ||||||
| 		cpumask_clear_cpu(cpu, mm_cpumask(t->mm)); |  | ||||||
| 		task_unlock(t); |  | ||||||
| 	} |  | ||||||
| 	rcu_read_unlock(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline void check_for_tasks(int cpu) |  | ||||||
| { |  | ||||||
| 	struct task_struct *p; |  | ||||||
|  |  | ||||||
| 	write_lock_irq(&tasklist_lock); |  | ||||||
| 	for_each_process(p) { |  | ||||||
| 		if (task_cpu(p) == cpu && p->state == TASK_RUNNING && |  | ||||||
| 		    (p->utime || p->stime)) |  | ||||||
| 			printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d " |  | ||||||
| 				"(state = %ld, flags = %x)\n", |  | ||||||
| 				p->comm, task_pid_nr(p), cpu, |  | ||||||
| 				p->state, p->flags); |  | ||||||
| 	} |  | ||||||
| 	write_unlock_irq(&tasklist_lock); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| struct take_cpu_down_param { |  | ||||||
| 	unsigned long mod; |  | ||||||
| 	void *hcpu; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* Take this CPU down. */ |  | ||||||
| static int __ref take_cpu_down(void *_param) |  | ||||||
| { |  | ||||||
| 	struct take_cpu_down_param *param = _param; |  | ||||||
| 	int err; |  | ||||||
|  |  | ||||||
| 	/* Ensure this CPU doesn't handle any more interrupts. */ |  | ||||||
| 	err = __cpu_disable(); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		return err; |  | ||||||
|  |  | ||||||
| 	cpu_notify(CPU_DYING | param->mod, param->hcpu); |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Requires cpu_add_remove_lock to be held */ |  | ||||||
| static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) |  | ||||||
| { |  | ||||||
| 	int err, nr_calls = 0; |  | ||||||
| 	void *hcpu = (void *)(long)cpu; |  | ||||||
| 	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; |  | ||||||
| 	struct take_cpu_down_param tcd_param = { |  | ||||||
| 		.mod = mod, |  | ||||||
| 		.hcpu = hcpu, |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	if (num_online_cpus() == 1) |  | ||||||
| 		return -EBUSY; |  | ||||||
|  |  | ||||||
| 	if (!cpu_online(cpu)) |  | ||||||
| 		return -EINVAL; |  | ||||||
|  |  | ||||||
| 	cpu_hotplug_begin(); |  | ||||||
|  |  | ||||||
| 	err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls); |  | ||||||
| 	if (err) { |  | ||||||
| 		nr_calls--; |  | ||||||
| 		__cpu_notify(CPU_DOWN_FAILED | mod, hcpu, nr_calls, NULL); |  | ||||||
| 		printk("%s: attempt to take down CPU %u failed\n", |  | ||||||
| 				__func__, cpu); |  | ||||||
| 		goto out_release; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu)); |  | ||||||
| 	if (err) { |  | ||||||
| 		/* CPU didn't die: tell everyone.  Can't complain. */ |  | ||||||
| 		cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu); |  | ||||||
|  |  | ||||||
| 		goto out_release; |  | ||||||
| 	} |  | ||||||
| 	BUG_ON(cpu_online(cpu)); |  | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	 * The migration_call() CPU_DYING callback will have removed all |  | ||||||
| 	 * runnable tasks from the cpu, there's only the idle task left now |  | ||||||
| 	 * that the migration thread is done doing the stop_machine thing. |  | ||||||
| 	 * |  | ||||||
| 	 * Wait for the stop thread to go away. |  | ||||||
| 	 */ |  | ||||||
| 	while (!idle_cpu(cpu)) |  | ||||||
| 		cpu_relax(); |  | ||||||
|  |  | ||||||
| 	/* This actually kills the CPU. */ |  | ||||||
| 	__cpu_die(cpu); |  | ||||||
|  |  | ||||||
| 	/* CPU is completely dead: tell everyone.  Too late to complain. */ |  | ||||||
| 	cpu_notify_nofail(CPU_DEAD | mod, hcpu); |  | ||||||
|  |  | ||||||
| 	check_for_tasks(cpu); |  | ||||||
|  |  | ||||||
| out_release: |  | ||||||
| 	cpu_hotplug_done(); |  | ||||||
| 	if (!err) |  | ||||||
| 		cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu); |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int __ref cpu_down(unsigned int cpu) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
|  |  | ||||||
| 	cpu_maps_update_begin(); |  | ||||||
|  |  | ||||||
| 	if (cpu_hotplug_disabled) { |  | ||||||
| 		err = -EBUSY; |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = _cpu_down(cpu, 0); |  | ||||||
|  |  | ||||||
| out: |  | ||||||
| 	cpu_maps_update_done(); |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(cpu_down); |  | ||||||
| #endif /*CONFIG_HOTPLUG_CPU*/ |  | ||||||
|  |  | ||||||
| /* Requires cpu_add_remove_lock to be held */ |  | ||||||
| static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) |  | ||||||
| { |  | ||||||
| 	int ret, nr_calls = 0; |  | ||||||
| 	void *hcpu = (void *)(long)cpu; |  | ||||||
| 	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; |  | ||||||
| 	struct task_struct *idle; |  | ||||||
|  |  | ||||||
| 	if (cpu_online(cpu) || !cpu_present(cpu)) |  | ||||||
| 		return -EINVAL; |  | ||||||
|  |  | ||||||
| 	cpu_hotplug_begin(); |  | ||||||
|  |  | ||||||
| 	idle = idle_thread_get(cpu); |  | ||||||
| 	if (IS_ERR(idle)) { |  | ||||||
| 		ret = PTR_ERR(idle); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls); |  | ||||||
| 	if (ret) { |  | ||||||
| 		nr_calls--; |  | ||||||
| 		printk(KERN_WARNING "%s: attempt to bring up CPU %u failed\n", |  | ||||||
| 				__func__, cpu); |  | ||||||
| 		goto out_notify; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Arch-specific enabling code. */ |  | ||||||
| 	ret = __cpu_up(cpu, idle); |  | ||||||
| 	if (ret != 0) |  | ||||||
| 		goto out_notify; |  | ||||||
| 	BUG_ON(!cpu_online(cpu)); |  | ||||||
|  |  | ||||||
| 	/* Now call notifier in preparation. */ |  | ||||||
| 	cpu_notify(CPU_ONLINE | mod, hcpu); |  | ||||||
|  |  | ||||||
| out_notify: |  | ||||||
| 	if (ret != 0) |  | ||||||
| 		__cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL); |  | ||||||
| out: |  | ||||||
| 	cpu_hotplug_done(); |  | ||||||
|  |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int __cpuinit cpu_up(unsigned int cpu) |  | ||||||
| { |  | ||||||
| 	int err = 0; |  | ||||||
|  |  | ||||||
| #ifdef	CONFIG_MEMORY_HOTPLUG |  | ||||||
| 	int nid; |  | ||||||
| 	pg_data_t	*pgdat; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	if (!cpu_possible(cpu)) { |  | ||||||
| 		printk(KERN_ERR "can't online cpu %d because it is not " |  | ||||||
| 			"configured as may-hotadd at boot time\n", cpu); |  | ||||||
| #if defined(CONFIG_IA64) |  | ||||||
| 		printk(KERN_ERR "please check additional_cpus= boot " |  | ||||||
| 				"parameter\n"); |  | ||||||
| #endif |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| #ifdef	CONFIG_MEMORY_HOTPLUG |  | ||||||
| 	nid = cpu_to_node(cpu); |  | ||||||
| 	if (!node_online(nid)) { |  | ||||||
| 		err = mem_online_node(nid); |  | ||||||
| 		if (err) |  | ||||||
| 			return err; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	pgdat = NODE_DATA(nid); |  | ||||||
| 	if (!pgdat) { |  | ||||||
| 		printk(KERN_ERR |  | ||||||
| 			"Can't online cpu %d due to NULL pgdat\n", cpu); |  | ||||||
| 		return -ENOMEM; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (pgdat->node_zonelists->_zonerefs->zone == NULL) { |  | ||||||
| 		mutex_lock(&zonelists_mutex); |  | ||||||
| 		build_all_zonelists(NULL); |  | ||||||
| 		mutex_unlock(&zonelists_mutex); |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	cpu_maps_update_begin(); |  | ||||||
|  |  | ||||||
| 	if (cpu_hotplug_disabled) { |  | ||||||
| 		err = -EBUSY; |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = _cpu_up(cpu, 0); |  | ||||||
|  |  | ||||||
| out: |  | ||||||
| 	cpu_maps_update_done(); |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(cpu_up); |  | ||||||
|  |  | ||||||
| #ifdef CONFIG_PM_SLEEP_SMP |  | ||||||
| static cpumask_var_t frozen_cpus; |  | ||||||
|  |  | ||||||
| void __weak arch_disable_nonboot_cpus_begin(void) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void __weak arch_disable_nonboot_cpus_end(void) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int disable_nonboot_cpus(void) |  | ||||||
| { |  | ||||||
| 	int cpu, first_cpu, error = 0; |  | ||||||
|  |  | ||||||
| 	cpu_maps_update_begin(); |  | ||||||
| 	first_cpu = cpumask_first(cpu_online_mask); |  | ||||||
| 	/* |  | ||||||
| 	 * We take down all of the non-boot CPUs in one shot to avoid races |  | ||||||
| 	 * with the userspace trying to use the CPU hotplug at the same time |  | ||||||
| 	 */ |  | ||||||
| 	cpumask_clear(frozen_cpus); |  | ||||||
| 	arch_disable_nonboot_cpus_begin(); |  | ||||||
|  |  | ||||||
| 	printk("Disabling non-boot CPUs ...\n"); |  | ||||||
| 	for_each_online_cpu(cpu) { |  | ||||||
| 		if (cpu == first_cpu) |  | ||||||
| 			continue; |  | ||||||
| 		error = _cpu_down(cpu, 1); |  | ||||||
| 		if (!error) |  | ||||||
| 			cpumask_set_cpu(cpu, frozen_cpus); |  | ||||||
| 		else { |  | ||||||
| 			printk(KERN_ERR "Error taking CPU%d down: %d\n", |  | ||||||
| 				cpu, error); |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	arch_disable_nonboot_cpus_end(); |  | ||||||
|  |  | ||||||
| 	if (!error) { |  | ||||||
| 		BUG_ON(num_online_cpus() > 1); |  | ||||||
| 		/* Make sure the CPUs won't be enabled by someone else */ |  | ||||||
| 		cpu_hotplug_disabled = 1; |  | ||||||
| 	} else { |  | ||||||
| 		printk(KERN_ERR "Non-boot CPUs are not disabled\n"); |  | ||||||
| 	} |  | ||||||
| 	cpu_maps_update_done(); |  | ||||||
| 	return error; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void __weak arch_enable_nonboot_cpus_begin(void) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void __weak arch_enable_nonboot_cpus_end(void) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void __ref enable_nonboot_cpus(void) |  | ||||||
| { |  | ||||||
| 	int cpu, error; |  | ||||||
|  |  | ||||||
| 	/* Allow everyone to use the CPU hotplug again */ |  | ||||||
| 	cpu_maps_update_begin(); |  | ||||||
| 	cpu_hotplug_disabled = 0; |  | ||||||
| 	if (cpumask_empty(frozen_cpus)) |  | ||||||
| 		goto out; |  | ||||||
|  |  | ||||||
| 	printk(KERN_INFO "Enabling non-boot CPUs ...\n"); |  | ||||||
|  |  | ||||||
| 	arch_enable_nonboot_cpus_begin(); |  | ||||||
|  |  | ||||||
| 	for_each_cpu(cpu, frozen_cpus) { |  | ||||||
| 		error = _cpu_up(cpu, 1); |  | ||||||
| 		if (!error) { |  | ||||||
| 			printk(KERN_INFO "CPU%d is up\n", cpu); |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
| 		printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	arch_enable_nonboot_cpus_end(); |  | ||||||
|  |  | ||||||
| 	cpumask_clear(frozen_cpus); |  | ||||||
| out: |  | ||||||
| 	cpu_maps_update_done(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int __init alloc_frozen_cpus(void) |  | ||||||
| { |  | ||||||
| 	if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO)) |  | ||||||
| 		return -ENOMEM; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| core_initcall(alloc_frozen_cpus); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Prevent regular CPU hotplug from racing with the freezer, by disabling CPU |  | ||||||
|  * hotplug when tasks are about to be frozen. Also, don't allow the freezer |  | ||||||
|  * to continue until any currently running CPU hotplug operation gets |  | ||||||
|  * completed. |  | ||||||
|  * To modify the 'cpu_hotplug_disabled' flag, we need to acquire the |  | ||||||
|  * 'cpu_add_remove_lock'. And this same lock is also taken by the regular |  | ||||||
|  * CPU hotplug path and released only after it is complete. Thus, we |  | ||||||
|  * (and hence the freezer) will block here until any currently running CPU |  | ||||||
|  * hotplug operation gets completed. |  | ||||||
|  */ |  | ||||||
| void cpu_hotplug_disable_before_freeze(void) |  | ||||||
| { |  | ||||||
| 	cpu_maps_update_begin(); |  | ||||||
| 	cpu_hotplug_disabled = 1; |  | ||||||
| 	cpu_maps_update_done(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * When tasks have been thawed, re-enable regular CPU hotplug (which had been |  | ||||||
|  * disabled while beginning to freeze tasks). |  | ||||||
|  */ |  | ||||||
| void cpu_hotplug_enable_after_thaw(void) |  | ||||||
| { |  | ||||||
| 	cpu_maps_update_begin(); |  | ||||||
| 	cpu_hotplug_disabled = 0; |  | ||||||
| 	cpu_maps_update_done(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * When callbacks for CPU hotplug notifications are being executed, we must |  | ||||||
|  * ensure that the state of the system with respect to the tasks being frozen |  | ||||||
|  * or not, as reported by the notification, remains unchanged *throughout the |  | ||||||
|  * duration* of the execution of the callbacks. |  | ||||||
|  * Hence we need to prevent the freezer from racing with regular CPU hotplug. |  | ||||||
|  * |  | ||||||
|  * This synchronization is implemented by mutually excluding regular CPU |  | ||||||
|  * hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/ |  | ||||||
|  * Hibernate notifications. |  | ||||||
|  */ |  | ||||||
| static int |  | ||||||
| cpu_hotplug_pm_callback(struct notifier_block *nb, |  | ||||||
| 			unsigned long action, void *ptr) |  | ||||||
| { |  | ||||||
| 	switch (action) { |  | ||||||
|  |  | ||||||
| 	case PM_SUSPEND_PREPARE: |  | ||||||
| 	case PM_HIBERNATION_PREPARE: |  | ||||||
| 		cpu_hotplug_disable_before_freeze(); |  | ||||||
| 		break; |  | ||||||
|  |  | ||||||
| 	case PM_POST_SUSPEND: |  | ||||||
| 	case PM_POST_HIBERNATION: |  | ||||||
| 		cpu_hotplug_enable_after_thaw(); |  | ||||||
| 		break; |  | ||||||
|  |  | ||||||
| 	default: |  | ||||||
| 		return NOTIFY_DONE; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return NOTIFY_OK; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static int __init cpu_hotplug_pm_sync_init(void) |  | ||||||
| { |  | ||||||
| 	pm_notifier(cpu_hotplug_pm_callback, 0); |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| core_initcall(cpu_hotplug_pm_sync_init); |  | ||||||
|  |  | ||||||
| #endif /* CONFIG_PM_SLEEP_SMP */ |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * notify_cpu_starting(cpu) - call the CPU_STARTING notifiers |  | ||||||
|  * @cpu: cpu that just started |  | ||||||
|  * |  | ||||||
|  * This function calls the cpu_chain notifiers with CPU_STARTING. |  | ||||||
|  * It must be called by the arch code on the new cpu, before the new cpu |  | ||||||
|  * enables interrupts and before the "boot" cpu returns from __cpu_up(). |  | ||||||
|  */ |  | ||||||
| void __cpuinit notify_cpu_starting(unsigned int cpu) |  | ||||||
| { |  | ||||||
| 	unsigned long val = CPU_STARTING; |  | ||||||
|  |  | ||||||
| #ifdef CONFIG_PM_SLEEP_SMP |  | ||||||
| 	if (frozen_cpus != NULL && cpumask_test_cpu(cpu, frozen_cpus)) |  | ||||||
| 		val = CPU_STARTING_FROZEN; |  | ||||||
| #endif /* CONFIG_PM_SLEEP_SMP */ |  | ||||||
| 	cpu_notify(val, (void *)(long)cpu); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif /* CONFIG_SMP */ |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * cpu_bit_bitmap[] is a special, "compressed" data structure that |  | ||||||
|  * represents all NR_CPUS bits binary values of 1<<nr. |  | ||||||
|  * |  | ||||||
|  * It is used by cpumask_of() to get a constant address to a CPU |  | ||||||
|  * mask value that has a single bit set only. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /* cpu_bit_bitmap[0] is empty - so we can back into it */ |  | ||||||
| #define MASK_DECLARE_1(x)	[x+1][0] = (1UL << (x)) |  | ||||||
| #define MASK_DECLARE_2(x)	MASK_DECLARE_1(x), MASK_DECLARE_1(x+1) |  | ||||||
| #define MASK_DECLARE_4(x)	MASK_DECLARE_2(x), MASK_DECLARE_2(x+2) |  | ||||||
| #define MASK_DECLARE_8(x)	MASK_DECLARE_4(x), MASK_DECLARE_4(x+4) |  | ||||||
|  |  | ||||||
| const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { |  | ||||||
|  |  | ||||||
| 	MASK_DECLARE_8(0),	MASK_DECLARE_8(8), |  | ||||||
| 	MASK_DECLARE_8(16),	MASK_DECLARE_8(24), |  | ||||||
| #if BITS_PER_LONG > 32 |  | ||||||
| 	MASK_DECLARE_8(32),	MASK_DECLARE_8(40), |  | ||||||
| 	MASK_DECLARE_8(48),	MASK_DECLARE_8(56), |  | ||||||
| #endif |  | ||||||
| }; |  | ||||||
| EXPORT_SYMBOL_GPL(cpu_bit_bitmap); |  | ||||||
|  |  | ||||||
| const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL; |  | ||||||
| EXPORT_SYMBOL(cpu_all_bits); |  | ||||||
|  |  | ||||||
| #ifdef CONFIG_INIT_ALL_POSSIBLE |  | ||||||
| static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly |  | ||||||
| 	= CPU_BITS_ALL; |  | ||||||
| #else |  | ||||||
| static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly; |  | ||||||
| #endif |  | ||||||
| const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits); |  | ||||||
| EXPORT_SYMBOL(cpu_possible_mask); |  | ||||||
|  |  | ||||||
| static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly; |  | ||||||
| const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits); |  | ||||||
| EXPORT_SYMBOL(cpu_online_mask); |  | ||||||
|  |  | ||||||
| static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly; |  | ||||||
| const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits); |  | ||||||
| EXPORT_SYMBOL(cpu_present_mask); |  | ||||||
|  |  | ||||||
| static DECLARE_BITMAP(cpu_active_bits, CONFIG_NR_CPUS) __read_mostly; |  | ||||||
| const struct cpumask *const cpu_active_mask = to_cpumask(cpu_active_bits); |  | ||||||
| EXPORT_SYMBOL(cpu_active_mask); |  | ||||||
|  |  | ||||||
| void set_cpu_possible(unsigned int cpu, bool possible) |  | ||||||
| { |  | ||||||
| 	if (possible) |  | ||||||
| 		cpumask_set_cpu(cpu, to_cpumask(cpu_possible_bits)); |  | ||||||
| 	else |  | ||||||
| 		cpumask_clear_cpu(cpu, to_cpumask(cpu_possible_bits)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void set_cpu_present(unsigned int cpu, bool present) |  | ||||||
| { |  | ||||||
| 	if (present) |  | ||||||
| 		cpumask_set_cpu(cpu, to_cpumask(cpu_present_bits)); |  | ||||||
| 	else |  | ||||||
| 		cpumask_clear_cpu(cpu, to_cpumask(cpu_present_bits)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void set_cpu_online(unsigned int cpu, bool online) |  | ||||||
| { |  | ||||||
| 	if (online) |  | ||||||
| 		cpumask_set_cpu(cpu, to_cpumask(cpu_online_bits)); |  | ||||||
| 	else |  | ||||||
| 		cpumask_clear_cpu(cpu, to_cpumask(cpu_online_bits)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void set_cpu_active(unsigned int cpu, bool active) |  | ||||||
| { |  | ||||||
| 	if (active) |  | ||||||
| 		cpumask_set_cpu(cpu, to_cpumask(cpu_active_bits)); |  | ||||||
| 	else |  | ||||||
| 		cpumask_clear_cpu(cpu, to_cpumask(cpu_active_bits)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void init_cpu_present(const struct cpumask *src) |  | ||||||
| { |  | ||||||
| 	cpumask_copy(to_cpumask(cpu_present_bits), src); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void init_cpu_possible(const struct cpumask *src) |  | ||||||
| { |  | ||||||
| 	cpumask_copy(to_cpumask(cpu_possible_bits), src); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void init_cpu_online(const struct cpumask *src) |  | ||||||
| { |  | ||||||
| 	cpumask_copy(to_cpumask(cpu_online_bits), src); |  | ||||||
| } |  | ||||||
							
								
								
									
										784
									
								
								samples/C/diff.c
									
									
									
									
									
								
							
							
						
						
									
										784
									
								
								samples/C/diff.c
									
									
									
									
									
								
							| @@ -1,784 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Copyright (C) 2012 the libgit2 contributors |  | ||||||
|  * |  | ||||||
|  * This file is part of libgit2, distributed under the GNU GPL v2 with |  | ||||||
|  * a Linking Exception. For full terms see the included COPYING file. |  | ||||||
|  */ |  | ||||||
| #include "common.h" |  | ||||||
| #include "git2/diff.h" |  | ||||||
| #include "diff.h" |  | ||||||
| #include "fileops.h" |  | ||||||
| #include "config.h" |  | ||||||
| #include "attr_file.h" |  | ||||||
|  |  | ||||||
| static char *diff_prefix_from_pathspec(const git_strarray *pathspec) |  | ||||||
| { |  | ||||||
| 	git_buf prefix = GIT_BUF_INIT; |  | ||||||
| 	const char *scan; |  | ||||||
|  |  | ||||||
| 	if (git_buf_common_prefix(&prefix, pathspec) < 0) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	/* diff prefix will only be leading non-wildcards */ |  | ||||||
| 	for (scan = prefix.ptr; *scan && !git__iswildcard(*scan); ++scan); |  | ||||||
| 	git_buf_truncate(&prefix, scan - prefix.ptr); |  | ||||||
|  |  | ||||||
| 	if (prefix.size > 0) |  | ||||||
| 		return git_buf_detach(&prefix); |  | ||||||
|  |  | ||||||
| 	git_buf_free(&prefix); |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static bool diff_pathspec_is_interesting(const git_strarray *pathspec) |  | ||||||
| { |  | ||||||
| 	const char *str; |  | ||||||
|  |  | ||||||
| 	if (pathspec == NULL || pathspec->count == 0) |  | ||||||
| 		return false; |  | ||||||
| 	if (pathspec->count > 1) |  | ||||||
| 		return true; |  | ||||||
|  |  | ||||||
| 	str = pathspec->strings[0]; |  | ||||||
| 	if (!str || !str[0] || (!str[1] && (str[0] == '*' || str[0] == '.'))) |  | ||||||
| 		return false; |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static bool diff_path_matches_pathspec(git_diff_list *diff, const char *path) |  | ||||||
| { |  | ||||||
| 	unsigned int i; |  | ||||||
| 	git_attr_fnmatch *match; |  | ||||||
|  |  | ||||||
| 	if (!diff->pathspec.length) |  | ||||||
| 		return true; |  | ||||||
|  |  | ||||||
| 	git_vector_foreach(&diff->pathspec, i, match) { |  | ||||||
| 		int result = p_fnmatch(match->pattern, path, 0); |  | ||||||
|  |  | ||||||
| 		/* if we didn't match, look for exact dirname prefix match */ |  | ||||||
| 		if (result == FNM_NOMATCH && |  | ||||||
| 			(match->flags & GIT_ATTR_FNMATCH_HASWILD) == 0 && |  | ||||||
| 			strncmp(path, match->pattern, match->length) == 0 && |  | ||||||
| 			path[match->length] == '/') |  | ||||||
| 			result = 0; |  | ||||||
|  |  | ||||||
| 		if (result == 0) |  | ||||||
| 			return (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) ? false : true; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static git_diff_delta *diff_delta__alloc( |  | ||||||
| 	git_diff_list *diff, |  | ||||||
| 	git_delta_t status, |  | ||||||
| 	const char *path) |  | ||||||
| { |  | ||||||
| 	git_diff_delta *delta = git__calloc(1, sizeof(git_diff_delta)); |  | ||||||
| 	if (!delta) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	delta->old_file.path = git_pool_strdup(&diff->pool, path); |  | ||||||
| 	if (delta->old_file.path == NULL) { |  | ||||||
| 		git__free(delta); |  | ||||||
| 		return NULL; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	delta->new_file.path = delta->old_file.path; |  | ||||||
|  |  | ||||||
| 	if (diff->opts.flags & GIT_DIFF_REVERSE) { |  | ||||||
| 		switch (status) { |  | ||||||
| 		case GIT_DELTA_ADDED:   status = GIT_DELTA_DELETED; break; |  | ||||||
| 		case GIT_DELTA_DELETED: status = GIT_DELTA_ADDED; break; |  | ||||||
| 		default: break; /* leave other status values alone */ |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	delta->status = status; |  | ||||||
|  |  | ||||||
| 	return delta; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static git_diff_delta *diff_delta__dup( |  | ||||||
| 	const git_diff_delta *d, git_pool *pool) |  | ||||||
| { |  | ||||||
| 	git_diff_delta *delta = git__malloc(sizeof(git_diff_delta)); |  | ||||||
| 	if (!delta) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	memcpy(delta, d, sizeof(git_diff_delta)); |  | ||||||
|  |  | ||||||
| 	delta->old_file.path = git_pool_strdup(pool, d->old_file.path); |  | ||||||
| 	if (delta->old_file.path == NULL) |  | ||||||
| 		goto fail; |  | ||||||
|  |  | ||||||
| 	if (d->new_file.path != d->old_file.path) { |  | ||||||
| 		delta->new_file.path = git_pool_strdup(pool, d->new_file.path); |  | ||||||
| 		if (delta->new_file.path == NULL) |  | ||||||
| 			goto fail; |  | ||||||
| 	} else { |  | ||||||
| 		delta->new_file.path = delta->old_file.path; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return delta; |  | ||||||
|  |  | ||||||
| fail: |  | ||||||
| 	git__free(delta); |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static git_diff_delta *diff_delta__merge_like_cgit( |  | ||||||
| 	const git_diff_delta *a, const git_diff_delta *b, git_pool *pool) |  | ||||||
| { |  | ||||||
| 	git_diff_delta *dup = diff_delta__dup(a, pool); |  | ||||||
| 	if (!dup) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	if (git_oid_cmp(&dup->new_file.oid, &b->new_file.oid) == 0) |  | ||||||
| 		return dup; |  | ||||||
|  |  | ||||||
| 	git_oid_cpy(&dup->new_file.oid, &b->new_file.oid); |  | ||||||
|  |  | ||||||
| 	dup->new_file.mode = b->new_file.mode; |  | ||||||
| 	dup->new_file.size = b->new_file.size; |  | ||||||
| 	dup->new_file.flags = b->new_file.flags; |  | ||||||
|  |  | ||||||
| 	/* Emulate C git for merging two diffs (a la 'git diff <sha>'). |  | ||||||
| 	 * |  | ||||||
| 	 * When C git does a diff between the work dir and a tree, it actually |  | ||||||
| 	 * diffs with the index but uses the workdir contents.  This emulates |  | ||||||
| 	 * those choices so we can emulate the type of diff. |  | ||||||
| 	 */ |  | ||||||
| 	if (git_oid_cmp(&dup->old_file.oid, &dup->new_file.oid) == 0) { |  | ||||||
| 		if (dup->status == GIT_DELTA_DELETED) |  | ||||||
| 			/* preserve pending delete info */; |  | ||||||
| 		else if (b->status == GIT_DELTA_UNTRACKED || |  | ||||||
| 				 b->status == GIT_DELTA_IGNORED) |  | ||||||
| 			dup->status = b->status; |  | ||||||
| 		else |  | ||||||
| 			dup->status = GIT_DELTA_UNMODIFIED; |  | ||||||
| 	} |  | ||||||
| 	else if (dup->status == GIT_DELTA_UNMODIFIED || |  | ||||||
| 			 b->status == GIT_DELTA_DELETED) |  | ||||||
| 		dup->status = b->status; |  | ||||||
|  |  | ||||||
| 	return dup; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int diff_delta__from_one( |  | ||||||
| 	git_diff_list *diff, |  | ||||||
| 	git_delta_t   status, |  | ||||||
| 	const git_index_entry *entry) |  | ||||||
| { |  | ||||||
| 	git_diff_delta *delta; |  | ||||||
|  |  | ||||||
| 	if (status == GIT_DELTA_IGNORED && |  | ||||||
| 		(diff->opts.flags & GIT_DIFF_INCLUDE_IGNORED) == 0) |  | ||||||
| 		return 0; |  | ||||||
|  |  | ||||||
| 	if (status == GIT_DELTA_UNTRACKED && |  | ||||||
| 		(diff->opts.flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0) |  | ||||||
| 		return 0; |  | ||||||
|  |  | ||||||
| 	if (!diff_path_matches_pathspec(diff, entry->path)) |  | ||||||
| 		return 0; |  | ||||||
|  |  | ||||||
| 	delta = diff_delta__alloc(diff, status, entry->path); |  | ||||||
| 	GITERR_CHECK_ALLOC(delta); |  | ||||||
|  |  | ||||||
| 	/* This fn is just for single-sided diffs */ |  | ||||||
| 	assert(status != GIT_DELTA_MODIFIED); |  | ||||||
|  |  | ||||||
| 	if (delta->status == GIT_DELTA_DELETED) { |  | ||||||
| 		delta->old_file.mode = entry->mode; |  | ||||||
| 		delta->old_file.size = entry->file_size; |  | ||||||
| 		git_oid_cpy(&delta->old_file.oid, &entry->oid); |  | ||||||
| 	} else /* ADDED, IGNORED, UNTRACKED */ { |  | ||||||
| 		delta->new_file.mode = entry->mode; |  | ||||||
| 		delta->new_file.size = entry->file_size; |  | ||||||
| 		git_oid_cpy(&delta->new_file.oid, &entry->oid); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	delta->old_file.flags |= GIT_DIFF_FILE_VALID_OID; |  | ||||||
| 	delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID; |  | ||||||
|  |  | ||||||
| 	if (git_vector_insert(&diff->deltas, delta) < 0) { |  | ||||||
| 		git__free(delta); |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int diff_delta__from_two( |  | ||||||
| 	git_diff_list *diff, |  | ||||||
| 	git_delta_t   status, |  | ||||||
| 	const git_index_entry *old_entry, |  | ||||||
| 	const git_index_entry *new_entry, |  | ||||||
| 	git_oid *new_oid) |  | ||||||
| { |  | ||||||
| 	git_diff_delta *delta; |  | ||||||
|  |  | ||||||
| 	if (status == GIT_DELTA_UNMODIFIED && |  | ||||||
| 		(diff->opts.flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0) |  | ||||||
| 		return 0; |  | ||||||
|  |  | ||||||
| 	if ((diff->opts.flags & GIT_DIFF_REVERSE) != 0) { |  | ||||||
| 		const git_index_entry *temp = old_entry; |  | ||||||
| 		old_entry = new_entry; |  | ||||||
| 		new_entry = temp; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	delta = diff_delta__alloc(diff, status, old_entry->path); |  | ||||||
| 	GITERR_CHECK_ALLOC(delta); |  | ||||||
|  |  | ||||||
| 	delta->old_file.mode = old_entry->mode; |  | ||||||
| 	git_oid_cpy(&delta->old_file.oid, &old_entry->oid); |  | ||||||
| 	delta->old_file.flags |= GIT_DIFF_FILE_VALID_OID; |  | ||||||
|  |  | ||||||
| 	delta->new_file.mode = new_entry->mode; |  | ||||||
| 	git_oid_cpy(&delta->new_file.oid, new_oid ? new_oid : &new_entry->oid); |  | ||||||
| 	if (new_oid || !git_oid_iszero(&new_entry->oid)) |  | ||||||
| 		delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID; |  | ||||||
|  |  | ||||||
| 	if (git_vector_insert(&diff->deltas, delta) < 0) { |  | ||||||
| 		git__free(delta); |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static char *diff_strdup_prefix(git_pool *pool, const char *prefix) |  | ||||||
| { |  | ||||||
| 	size_t len = strlen(prefix); |  | ||||||
|  |  | ||||||
| 	/* append '/' at end if needed */ |  | ||||||
| 	if (len > 0 && prefix[len - 1] != '/') |  | ||||||
| 		return git_pool_strcat(pool, prefix, "/"); |  | ||||||
| 	else |  | ||||||
| 		return git_pool_strndup(pool, prefix, len + 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int diff_delta__cmp(const void *a, const void *b) |  | ||||||
| { |  | ||||||
| 	const git_diff_delta *da = a, *db = b; |  | ||||||
| 	int val = strcmp(da->old_file.path, db->old_file.path); |  | ||||||
| 	return val ? val : ((int)da->status - (int)db->status); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int config_bool(git_config *cfg, const char *name, int defvalue) |  | ||||||
| { |  | ||||||
| 	int val = defvalue; |  | ||||||
|  |  | ||||||
| 	if (git_config_get_bool(&val, cfg, name) < 0) |  | ||||||
| 		giterr_clear(); |  | ||||||
|  |  | ||||||
| 	return val; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static git_diff_list *git_diff_list_alloc( |  | ||||||
| 	git_repository *repo, const git_diff_options *opts) |  | ||||||
| { |  | ||||||
| 	git_config *cfg; |  | ||||||
| 	size_t i; |  | ||||||
| 	git_diff_list *diff = git__calloc(1, sizeof(git_diff_list)); |  | ||||||
| 	if (diff == NULL) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	diff->repo = repo; |  | ||||||
|  |  | ||||||
| 	if (git_vector_init(&diff->deltas, 0, diff_delta__cmp) < 0 || |  | ||||||
| 		git_pool_init(&diff->pool, 1, 0) < 0) |  | ||||||
| 		goto fail; |  | ||||||
|  |  | ||||||
| 	/* load config values that affect diff behavior */ |  | ||||||
| 	if (git_repository_config__weakptr(&cfg, repo) < 0) |  | ||||||
| 		goto fail; |  | ||||||
| 	if (config_bool(cfg, "core.symlinks", 1)) |  | ||||||
| 		diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS; |  | ||||||
| 	if (config_bool(cfg, "core.ignorestat", 0)) |  | ||||||
| 		diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED; |  | ||||||
| 	if (config_bool(cfg, "core.filemode", 1)) |  | ||||||
| 		diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_EXEC_BIT; |  | ||||||
| 	if (config_bool(cfg, "core.trustctime", 1)) |  | ||||||
| 		diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME; |  | ||||||
| 	/* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */ |  | ||||||
|  |  | ||||||
| 	if (opts == NULL) |  | ||||||
| 		return diff; |  | ||||||
|  |  | ||||||
| 	memcpy(&diff->opts, opts, sizeof(git_diff_options)); |  | ||||||
| 	memset(&diff->opts.pathspec, 0, sizeof(diff->opts.pathspec)); |  | ||||||
|  |  | ||||||
| 	diff->opts.old_prefix = diff_strdup_prefix(&diff->pool, |  | ||||||
| 		opts->old_prefix ? opts->old_prefix : DIFF_OLD_PREFIX_DEFAULT); |  | ||||||
| 	diff->opts.new_prefix = diff_strdup_prefix(&diff->pool, |  | ||||||
| 		opts->new_prefix ? opts->new_prefix : DIFF_NEW_PREFIX_DEFAULT); |  | ||||||
|  |  | ||||||
| 	if (!diff->opts.old_prefix || !diff->opts.new_prefix) |  | ||||||
| 		goto fail; |  | ||||||
|  |  | ||||||
| 	if (diff->opts.flags & GIT_DIFF_REVERSE) { |  | ||||||
| 		char *swap = diff->opts.old_prefix; |  | ||||||
| 		diff->opts.old_prefix = diff->opts.new_prefix; |  | ||||||
| 		diff->opts.new_prefix = swap; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* only copy pathspec if it is "interesting" so we can test |  | ||||||
| 	 * diff->pathspec.length > 0 to know if it is worth calling |  | ||||||
| 	 * fnmatch as we iterate. |  | ||||||
| 	 */ |  | ||||||
| 	if (!diff_pathspec_is_interesting(&opts->pathspec)) |  | ||||||
| 		return diff; |  | ||||||
|  |  | ||||||
| 	if (git_vector_init( |  | ||||||
| 		&diff->pathspec, (unsigned int)opts->pathspec.count, NULL) < 0) |  | ||||||
| 		goto fail; |  | ||||||
|  |  | ||||||
| 	for (i = 0; i < opts->pathspec.count; ++i) { |  | ||||||
| 		int ret; |  | ||||||
| 		const char *pattern = opts->pathspec.strings[i]; |  | ||||||
| 		git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch)); |  | ||||||
| 		if (!match) |  | ||||||
| 			goto fail; |  | ||||||
| 		match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE; |  | ||||||
| 		ret = git_attr_fnmatch__parse(match, &diff->pool, NULL, &pattern); |  | ||||||
| 		if (ret == GIT_ENOTFOUND) { |  | ||||||
| 			git__free(match); |  | ||||||
| 			continue; |  | ||||||
| 		} else if (ret < 0) |  | ||||||
| 			goto fail; |  | ||||||
|  |  | ||||||
| 		if (git_vector_insert(&diff->pathspec, match) < 0) |  | ||||||
| 			goto fail; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return diff; |  | ||||||
|  |  | ||||||
| fail: |  | ||||||
| 	git_diff_list_free(diff); |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void git_diff_list_free(git_diff_list *diff) |  | ||||||
| { |  | ||||||
| 	git_diff_delta *delta; |  | ||||||
| 	git_attr_fnmatch *match; |  | ||||||
| 	unsigned int i; |  | ||||||
|  |  | ||||||
| 	if (!diff) |  | ||||||
| 		return; |  | ||||||
|  |  | ||||||
| 	git_vector_foreach(&diff->deltas, i, delta) { |  | ||||||
| 		git__free(delta); |  | ||||||
| 		diff->deltas.contents[i] = NULL; |  | ||||||
| 	} |  | ||||||
| 	git_vector_free(&diff->deltas); |  | ||||||
|  |  | ||||||
| 	git_vector_foreach(&diff->pathspec, i, match) { |  | ||||||
| 		git__free(match); |  | ||||||
| 		diff->pathspec.contents[i] = NULL; |  | ||||||
| 	} |  | ||||||
| 	git_vector_free(&diff->pathspec); |  | ||||||
|  |  | ||||||
| 	git_pool_clear(&diff->pool); |  | ||||||
| 	git__free(diff); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int oid_for_workdir_item( |  | ||||||
| 	git_repository *repo, |  | ||||||
| 	const git_index_entry *item, |  | ||||||
| 	git_oid *oid) |  | ||||||
| { |  | ||||||
| 	int result; |  | ||||||
| 	git_buf full_path = GIT_BUF_INIT; |  | ||||||
|  |  | ||||||
| 	if (git_buf_joinpath(&full_path, git_repository_workdir(repo), item->path) < 0) |  | ||||||
| 		return -1; |  | ||||||
|  |  | ||||||
| 	/* calculate OID for file if possible*/ |  | ||||||
| 	if (S_ISLNK(item->mode)) |  | ||||||
| 		result = git_odb__hashlink(oid, full_path.ptr); |  | ||||||
| 	else if (!git__is_sizet(item->file_size)) { |  | ||||||
| 		giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); |  | ||||||
| 		result = -1; |  | ||||||
| 	} else { |  | ||||||
| 		int fd = git_futils_open_ro(full_path.ptr); |  | ||||||
| 		if (fd < 0) |  | ||||||
| 			result = fd; |  | ||||||
| 		else { |  | ||||||
| 			result = git_odb__hashfd( |  | ||||||
| 				oid, fd, (size_t)item->file_size, GIT_OBJ_BLOB); |  | ||||||
| 			p_close(fd); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	git_buf_free(&full_path); |  | ||||||
|  |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define EXEC_BIT_MASK 0000111 |  | ||||||
|  |  | ||||||
| static int maybe_modified( |  | ||||||
| 	git_iterator *old_iter, |  | ||||||
| 	const git_index_entry *oitem, |  | ||||||
| 	git_iterator *new_iter, |  | ||||||
| 	const git_index_entry *nitem, |  | ||||||
| 	git_diff_list *diff) |  | ||||||
| { |  | ||||||
| 	git_oid noid, *use_noid = NULL; |  | ||||||
| 	git_delta_t status = GIT_DELTA_MODIFIED; |  | ||||||
| 	unsigned int omode = oitem->mode; |  | ||||||
| 	unsigned int nmode = nitem->mode; |  | ||||||
|  |  | ||||||
| 	GIT_UNUSED(old_iter); |  | ||||||
|  |  | ||||||
| 	if (!diff_path_matches_pathspec(diff, oitem->path)) |  | ||||||
| 		return 0; |  | ||||||
|  |  | ||||||
| 	/* on platforms with no symlinks, promote plain files to symlinks */ |  | ||||||
| 	if (S_ISLNK(omode) && S_ISREG(nmode) && |  | ||||||
| 		!(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS)) |  | ||||||
| 		nmode = GIT_MODE_TYPE(omode) | (nmode & GIT_MODE_PERMS_MASK); |  | ||||||
|  |  | ||||||
| 	/* on platforms with no execmode, clear exec bit from comparisons */ |  | ||||||
| 	if (!(diff->diffcaps & GIT_DIFFCAPS_TRUST_EXEC_BIT)) { |  | ||||||
| 		omode = omode & ~EXEC_BIT_MASK; |  | ||||||
| 		nmode = nmode & ~EXEC_BIT_MASK; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* support "assume unchanged" (badly, b/c we still stat everything) */ |  | ||||||
| 	if ((diff->diffcaps & GIT_DIFFCAPS_ASSUME_UNCHANGED) != 0) |  | ||||||
| 		status = (oitem->flags_extended & GIT_IDXENTRY_INTENT_TO_ADD) ? |  | ||||||
| 			GIT_DELTA_MODIFIED : GIT_DELTA_UNMODIFIED; |  | ||||||
|  |  | ||||||
| 	/* support "skip worktree" index bit */ |  | ||||||
| 	else if ((oitem->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE) != 0) |  | ||||||
| 		status = GIT_DELTA_UNMODIFIED; |  | ||||||
|  |  | ||||||
| 	/* if basic type of file changed, then split into delete and add */ |  | ||||||
| 	else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) { |  | ||||||
| 		if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 || |  | ||||||
| 			diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0) |  | ||||||
| 			return -1; |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* if oids and modes match, then file is unmodified */ |  | ||||||
| 	else if (git_oid_cmp(&oitem->oid, &nitem->oid) == 0 && |  | ||||||
| 			 omode == nmode) |  | ||||||
| 		status = GIT_DELTA_UNMODIFIED; |  | ||||||
|  |  | ||||||
| 	/* if we have a workdir item with an unknown oid, check deeper */ |  | ||||||
| 	else if (git_oid_iszero(&nitem->oid) && new_iter->type == GIT_ITERATOR_WORKDIR) { |  | ||||||
| 		/* TODO: add check against index file st_mtime to avoid racy-git */ |  | ||||||
|  |  | ||||||
| 		/* if they files look exactly alike, then we'll assume the same */ |  | ||||||
| 		if (oitem->file_size == nitem->file_size && |  | ||||||
| 			(!(diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) || |  | ||||||
| 			 (oitem->ctime.seconds == nitem->ctime.seconds)) && |  | ||||||
| 			oitem->mtime.seconds == nitem->mtime.seconds && |  | ||||||
| 			(!(diff->diffcaps & GIT_DIFFCAPS_USE_DEV) || |  | ||||||
| 			 (oitem->dev == nitem->dev)) && |  | ||||||
| 			oitem->ino == nitem->ino && |  | ||||||
| 			oitem->uid == nitem->uid && |  | ||||||
| 			oitem->gid == nitem->gid) |  | ||||||
| 			status = GIT_DELTA_UNMODIFIED; |  | ||||||
|  |  | ||||||
| 		else if (S_ISGITLINK(nmode)) { |  | ||||||
| 			git_submodule *sub; |  | ||||||
|  |  | ||||||
| 			if ((diff->opts.flags & GIT_DIFF_IGNORE_SUBMODULES) != 0) |  | ||||||
| 				status = GIT_DELTA_UNMODIFIED; |  | ||||||
| 			else if (git_submodule_lookup(&sub, diff->repo, nitem->path) < 0) |  | ||||||
| 				return -1; |  | ||||||
| 			else if (sub->ignore == GIT_SUBMODULE_IGNORE_ALL) |  | ||||||
| 				status = GIT_DELTA_UNMODIFIED; |  | ||||||
| 			else { |  | ||||||
| 				/* TODO: support other GIT_SUBMODULE_IGNORE values */ |  | ||||||
| 				status = GIT_DELTA_UNMODIFIED; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		/* TODO: check git attributes so we will not have to read the file |  | ||||||
| 		 * in if it is marked binary. |  | ||||||
| 		 */ |  | ||||||
|  |  | ||||||
| 		else if (oid_for_workdir_item(diff->repo, nitem, &noid) < 0) |  | ||||||
| 			return -1; |  | ||||||
|  |  | ||||||
| 		else if (git_oid_cmp(&oitem->oid, &noid) == 0 && |  | ||||||
| 				 omode == nmode) |  | ||||||
| 			status = GIT_DELTA_UNMODIFIED; |  | ||||||
|  |  | ||||||
| 		/* store calculated oid so we don't have to recalc later */ |  | ||||||
| 		use_noid = &noid; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return diff_delta__from_two(diff, status, oitem, nitem, use_noid); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int diff_from_iterators( |  | ||||||
| 	git_repository *repo, |  | ||||||
| 	const git_diff_options *opts, /**< can be NULL for defaults */ |  | ||||||
| 	git_iterator *old_iter, |  | ||||||
| 	git_iterator *new_iter, |  | ||||||
| 	git_diff_list **diff_ptr) |  | ||||||
| { |  | ||||||
| 	const git_index_entry *oitem, *nitem; |  | ||||||
| 	git_buf ignore_prefix = GIT_BUF_INIT; |  | ||||||
| 	git_diff_list *diff = git_diff_list_alloc(repo, opts); |  | ||||||
| 	if (!diff) |  | ||||||
| 		goto fail; |  | ||||||
|  |  | ||||||
| 	diff->old_src = old_iter->type; |  | ||||||
| 	diff->new_src = new_iter->type; |  | ||||||
|  |  | ||||||
| 	if (git_iterator_current(old_iter, &oitem) < 0 || |  | ||||||
| 		git_iterator_current(new_iter, &nitem) < 0) |  | ||||||
| 		goto fail; |  | ||||||
|  |  | ||||||
| 	/* run iterators building diffs */ |  | ||||||
| 	while (oitem || nitem) { |  | ||||||
|  |  | ||||||
| 		/* create DELETED records for old items not matched in new */ |  | ||||||
| 		if (oitem && (!nitem || strcmp(oitem->path, nitem->path) < 0)) { |  | ||||||
| 			if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 || |  | ||||||
| 				git_iterator_advance(old_iter, &oitem) < 0) |  | ||||||
| 				goto fail; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		/* create ADDED, TRACKED, or IGNORED records for new items not |  | ||||||
| 		 * matched in old (and/or descend into directories as needed) |  | ||||||
| 		 */ |  | ||||||
| 		else if (nitem && (!oitem || strcmp(oitem->path, nitem->path) > 0)) { |  | ||||||
| 			git_delta_t delta_type = GIT_DELTA_UNTRACKED; |  | ||||||
|  |  | ||||||
| 			/* check if contained in ignored parent directory */ |  | ||||||
| 			if (git_buf_len(&ignore_prefix) && |  | ||||||
| 				git__prefixcmp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0) |  | ||||||
| 				delta_type = GIT_DELTA_IGNORED; |  | ||||||
|  |  | ||||||
| 			if (S_ISDIR(nitem->mode)) { |  | ||||||
| 				/* recurse into directory only if there are tracked items in |  | ||||||
| 				 * it or if the user requested the contents of untracked |  | ||||||
| 				 * directories and it is not under an ignored directory. |  | ||||||
| 				 */ |  | ||||||
| 				if ((oitem && git__prefixcmp(oitem->path, nitem->path) == 0) || |  | ||||||
| 					(delta_type == GIT_DELTA_UNTRACKED && |  | ||||||
| 					 (diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) != 0)) |  | ||||||
| 				{ |  | ||||||
| 					/* if this directory is ignored, remember it as the |  | ||||||
| 					 * "ignore_prefix" for processing contained items |  | ||||||
| 					 */ |  | ||||||
| 					if (delta_type == GIT_DELTA_UNTRACKED && |  | ||||||
| 						git_iterator_current_is_ignored(new_iter)) |  | ||||||
| 						git_buf_sets(&ignore_prefix, nitem->path); |  | ||||||
|  |  | ||||||
| 					if (git_iterator_advance_into_directory(new_iter, &nitem) < 0) |  | ||||||
| 						goto fail; |  | ||||||
|  |  | ||||||
| 					continue; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			/* In core git, the next two "else if" clauses are effectively |  | ||||||
| 			 * reversed -- i.e. when an untracked file contained in an |  | ||||||
| 			 * ignored directory is individually ignored, it shows up as an |  | ||||||
| 			 * ignored file in the diff list, even though other untracked |  | ||||||
| 			 * files in the same directory are skipped completely. |  | ||||||
| 			 * |  | ||||||
| 			 * To me, this is odd.  If the directory is ignored and the file |  | ||||||
| 			 * is untracked, we should skip it consistently, regardless of |  | ||||||
| 			 * whether it happens to match a pattern in the ignore file. |  | ||||||
| 			 * |  | ||||||
| 			 * To match the core git behavior, just reverse the following |  | ||||||
| 			 * two "else if" cases so that individual file ignores are |  | ||||||
| 			 * checked before container directory exclusions are used to |  | ||||||
| 			 * skip the file. |  | ||||||
| 			 */ |  | ||||||
| 			else if (delta_type == GIT_DELTA_IGNORED) { |  | ||||||
| 				if (git_iterator_advance(new_iter, &nitem) < 0) |  | ||||||
| 					goto fail; |  | ||||||
| 				continue; /* ignored parent directory, so skip completely */ |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			else if (git_iterator_current_is_ignored(new_iter)) |  | ||||||
| 				delta_type = GIT_DELTA_IGNORED; |  | ||||||
|  |  | ||||||
| 			else if (new_iter->type != GIT_ITERATOR_WORKDIR) |  | ||||||
| 				delta_type = GIT_DELTA_ADDED; |  | ||||||
|  |  | ||||||
| 			if (diff_delta__from_one(diff, delta_type, nitem) < 0 || |  | ||||||
| 				git_iterator_advance(new_iter, &nitem) < 0) |  | ||||||
| 				goto fail; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		/* otherwise item paths match, so create MODIFIED record |  | ||||||
| 		 * (or ADDED and DELETED pair if type changed) |  | ||||||
| 		 */ |  | ||||||
| 		else { |  | ||||||
| 			assert(oitem && nitem && strcmp(oitem->path, nitem->path) == 0); |  | ||||||
|  |  | ||||||
| 			if (maybe_modified(old_iter, oitem, new_iter, nitem, diff) < 0 || |  | ||||||
| 				git_iterator_advance(old_iter, &oitem) < 0 || |  | ||||||
| 				git_iterator_advance(new_iter, &nitem) < 0) |  | ||||||
| 				goto fail; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	git_iterator_free(old_iter); |  | ||||||
| 	git_iterator_free(new_iter); |  | ||||||
| 	git_buf_free(&ignore_prefix); |  | ||||||
|  |  | ||||||
| 	*diff_ptr = diff; |  | ||||||
| 	return 0; |  | ||||||
|  |  | ||||||
| fail: |  | ||||||
| 	git_iterator_free(old_iter); |  | ||||||
| 	git_iterator_free(new_iter); |  | ||||||
| 	git_buf_free(&ignore_prefix); |  | ||||||
|  |  | ||||||
| 	git_diff_list_free(diff); |  | ||||||
| 	*diff_ptr = NULL; |  | ||||||
| 	return -1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int git_diff_tree_to_tree( |  | ||||||
| 	git_repository *repo, |  | ||||||
| 	const git_diff_options *opts, /**< can be NULL for defaults */ |  | ||||||
| 	git_tree *old_tree, |  | ||||||
| 	git_tree *new_tree, |  | ||||||
| 	git_diff_list **diff) |  | ||||||
| { |  | ||||||
| 	git_iterator *a = NULL, *b = NULL; |  | ||||||
| 	char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; |  | ||||||
|  |  | ||||||
| 	assert(repo && old_tree && new_tree && diff); |  | ||||||
|  |  | ||||||
| 	if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || |  | ||||||
| 		git_iterator_for_tree_range(&b, repo, new_tree, prefix, prefix) < 0) |  | ||||||
| 		return -1; |  | ||||||
|  |  | ||||||
| 	git__free(prefix); |  | ||||||
|  |  | ||||||
| 	return diff_from_iterators(repo, opts, a, b, diff); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int git_diff_index_to_tree( |  | ||||||
| 	git_repository *repo, |  | ||||||
| 	const git_diff_options *opts, |  | ||||||
| 	git_tree *old_tree, |  | ||||||
| 	git_diff_list **diff) |  | ||||||
| { |  | ||||||
| 	git_iterator *a = NULL, *b = NULL; |  | ||||||
| 	char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; |  | ||||||
|  |  | ||||||
| 	assert(repo && diff); |  | ||||||
|  |  | ||||||
| 	if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || |  | ||||||
| 		git_iterator_for_index_range(&b, repo, prefix, prefix) < 0) |  | ||||||
| 		return -1; |  | ||||||
|  |  | ||||||
| 	git__free(prefix); |  | ||||||
|  |  | ||||||
| 	return diff_from_iterators(repo, opts, a, b, diff); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int git_diff_workdir_to_index( |  | ||||||
| 	git_repository *repo, |  | ||||||
| 	const git_diff_options *opts, |  | ||||||
| 	git_diff_list **diff) |  | ||||||
| { |  | ||||||
| 	git_iterator *a = NULL, *b = NULL; |  | ||||||
| 	char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; |  | ||||||
|  |  | ||||||
| 	assert(repo && diff); |  | ||||||
|  |  | ||||||
| 	if (git_iterator_for_index_range(&a, repo, prefix, prefix) < 0 || |  | ||||||
| 		git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0) |  | ||||||
| 		return -1; |  | ||||||
|  |  | ||||||
| 	git__free(prefix); |  | ||||||
|  |  | ||||||
| 	return diff_from_iterators(repo, opts, a, b, diff); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int git_diff_workdir_to_tree( |  | ||||||
| 	git_repository *repo, |  | ||||||
| 	const git_diff_options *opts, |  | ||||||
| 	git_tree *old_tree, |  | ||||||
| 	git_diff_list **diff) |  | ||||||
| { |  | ||||||
| 	git_iterator *a = NULL, *b = NULL; |  | ||||||
| 	char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; |  | ||||||
|  |  | ||||||
| 	assert(repo && old_tree && diff); |  | ||||||
|  |  | ||||||
| 	if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || |  | ||||||
| 		git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0) |  | ||||||
| 		return -1; |  | ||||||
|  |  | ||||||
| 	git__free(prefix); |  | ||||||
|  |  | ||||||
| 	return diff_from_iterators(repo, opts, a, b, diff); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int git_diff_merge( |  | ||||||
| 	git_diff_list *onto, |  | ||||||
| 	const git_diff_list *from) |  | ||||||
| { |  | ||||||
| 	int error = 0; |  | ||||||
| 	git_pool onto_pool; |  | ||||||
| 	git_vector onto_new; |  | ||||||
| 	git_diff_delta *delta; |  | ||||||
| 	unsigned int i, j; |  | ||||||
|  |  | ||||||
| 	assert(onto && from); |  | ||||||
|  |  | ||||||
| 	if (!from->deltas.length) |  | ||||||
| 		return 0; |  | ||||||
|  |  | ||||||
| 	if (git_vector_init(&onto_new, onto->deltas.length, diff_delta__cmp) < 0 || |  | ||||||
| 		git_pool_init(&onto_pool, 1, 0) < 0) |  | ||||||
| 		return -1; |  | ||||||
|  |  | ||||||
| 	for (i = 0, j = 0; i < onto->deltas.length || j < from->deltas.length; ) { |  | ||||||
| 		git_diff_delta *o = GIT_VECTOR_GET(&onto->deltas, i); |  | ||||||
| 		const git_diff_delta *f = GIT_VECTOR_GET(&from->deltas, j); |  | ||||||
| 		int cmp = !f ? -1 : !o ? 1 : strcmp(o->old_file.path, f->old_file.path); |  | ||||||
|  |  | ||||||
| 		if (cmp < 0) { |  | ||||||
| 			delta = diff_delta__dup(o, &onto_pool); |  | ||||||
| 			i++; |  | ||||||
| 		} else if (cmp > 0) { |  | ||||||
| 			delta = diff_delta__dup(f, &onto_pool); |  | ||||||
| 			j++; |  | ||||||
| 		} else { |  | ||||||
| 			delta = diff_delta__merge_like_cgit(o, f, &onto_pool); |  | ||||||
| 			i++; |  | ||||||
| 			j++; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if ((error = !delta ? -1 : git_vector_insert(&onto_new, delta)) < 0) |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (!error) { |  | ||||||
| 		git_vector_swap(&onto->deltas, &onto_new); |  | ||||||
| 		git_pool_swap(&onto->pool, &onto_pool); |  | ||||||
| 		onto->new_src = from->new_src; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	git_vector_foreach(&onto_new, i, delta) |  | ||||||
| 		git__free(delta); |  | ||||||
| 	git_vector_free(&onto_new); |  | ||||||
| 	git_pool_clear(&onto_pool); |  | ||||||
|  |  | ||||||
| 	return error; |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										188
									
								
								samples/C/fudge_node.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								samples/C/fudge_node.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,188 @@ | |||||||
|  | /* Copyright (c) 2010 Jens Nyberg | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person | ||||||
|  | obtaining a copy of this software and associated documentation | ||||||
|  | files (the "Software"), to deal in the Software without | ||||||
|  | restriction, including without limitation the rights to use, | ||||||
|  | copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the | ||||||
|  | Software is furnished to do so, subject to the following | ||||||
|  | conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be | ||||||
|  | included in all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||||||
|  | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||||||
|  | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||||
|  | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||||
|  | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||||
|  | OTHER DEALINGS IN THE SOFTWARE. */ | ||||||
|  |  | ||||||
|  | #include <fudge.h> | ||||||
|  | #include <kernel.h> | ||||||
|  | #include <modules/system/system.h> | ||||||
|  | #include "pipe.h" | ||||||
|  |  | ||||||
|  | static struct system_node root; | ||||||
|  | static struct system_node clone; | ||||||
|  |  | ||||||
|  | static unsigned int read(struct pipe_end *endself, struct pipe_end *endtarget, struct service_state *state, unsigned int count, void *buffer) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     count = buffer_rcfifo(&endself->buffer, count, buffer); | ||||||
|  |  | ||||||
|  |     if (!count && endtarget->node.refcount) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         list_add(&endself->readlinks, &state->link); | ||||||
|  |         task_setstatus(state->link.data, TASK_STATUS_BLOCKED); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     system_wakeup(&endtarget->writelinks); | ||||||
|  |  | ||||||
|  |     return count; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static unsigned int write(struct pipe_end *endself, struct pipe_end *endtarget, struct service_state *state, unsigned int count, void *buffer) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     count = buffer_wcfifo(&endtarget->buffer, count, buffer); | ||||||
|  |  | ||||||
|  |     if (!count) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         list_add(&endself->writelinks, &state->link); | ||||||
|  |         task_setstatus(state->link.data, TASK_STATUS_BLOCKED); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     system_wakeup(&endtarget->readlinks); | ||||||
|  |  | ||||||
|  |     return count; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static unsigned int end0_read(struct system_node *self, struct service_state *state, unsigned int count, void *buffer) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     struct pipe *pipe = (struct pipe *)self->parent; | ||||||
|  |  | ||||||
|  |     return read(&pipe->end0, &pipe->end1, state, count, buffer); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static unsigned int end0_write(struct system_node *self, struct service_state *state, unsigned int count, void *buffer) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     struct pipe *pipe = (struct pipe *)self->parent; | ||||||
|  |  | ||||||
|  |     return write(&pipe->end0, &pipe->end1, state, count, buffer); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static unsigned int end1_read(struct system_node *self, struct service_state *state, unsigned int count, void *buffer) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     struct pipe *pipe = (struct pipe *)self->parent; | ||||||
|  |  | ||||||
|  |     return read(&pipe->end1, &pipe->end0, state, count, buffer); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static unsigned int end1_write(struct system_node *self, struct service_state *state, unsigned int count, void *buffer) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     struct pipe *pipe = (struct pipe *)self->parent; | ||||||
|  |  | ||||||
|  |     return write(&pipe->end1, &pipe->end0, state, count, buffer); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static unsigned int clone_child(struct system_node *self, unsigned int count, char *path) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     struct list_item *current; | ||||||
|  |  | ||||||
|  |     for (current = root.children.head; current; current = current->next) | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         struct system_node *node = current->data; | ||||||
|  |         struct pipe *pipe = current->data; | ||||||
|  |  | ||||||
|  |         if (node == self) | ||||||
|  |             continue; | ||||||
|  |  | ||||||
|  |         if (pipe->end0.node.refcount || pipe->end1.node.refcount) | ||||||
|  |             continue; | ||||||
|  |  | ||||||
|  |         return node->child(node, count, path); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void pipe_init(struct pipe *pipe) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     buffer_init(&pipe->end0.buffer, 4096, pipe->end0.data); | ||||||
|  |     buffer_init(&pipe->end1.buffer, 4096, pipe->end1.data); | ||||||
|  |     system_initnode(&pipe->end0.node, SYSTEM_NODETYPE_NORMAL, "0"); | ||||||
|  |     system_initnode(&pipe->end1.node, SYSTEM_NODETYPE_NORMAL, "1"); | ||||||
|  |  | ||||||
|  |     pipe->end0.node.read = end0_read; | ||||||
|  |     pipe->end0.node.write = end0_write; | ||||||
|  |     pipe->end1.node.read = end1_read; | ||||||
|  |     pipe->end1.node.write = end1_write; | ||||||
|  |  | ||||||
|  |     system_initnode(&pipe->root, SYSTEM_NODETYPE_GROUP | SYSTEM_NODETYPE_MULTI, "pipe"); | ||||||
|  |     system_addchild(&pipe->root, &pipe->end0.node); | ||||||
|  |     system_addchild(&pipe->root, &pipe->end1.node); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void pipe_register(struct pipe *pipe) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     system_addchild(&root, &pipe->root); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void pipe_unregister(struct pipe *pipe) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     system_removechild(&root, &pipe->root); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void module_init(void) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     system_initnode(&root, SYSTEM_NODETYPE_GROUP, "pipe"); | ||||||
|  |     system_initnode(&clone, SYSTEM_NODETYPE_GROUP, "clone"); | ||||||
|  |  | ||||||
|  |     clone.child = clone_child; | ||||||
|  |  | ||||||
|  |     system_addchild(&root, &clone); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void module_register(void) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     system_registernode(&root); | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void module_unregister(void) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     system_unregisternode(&root); | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1,74 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Copyright (C) 2009-2012 the libgit2 contributors |  | ||||||
|  * |  | ||||||
|  * This file is part of libgit2, distributed under the GNU GPL v2 with |  | ||||||
|  * a Linking Exception. For full terms see the included COPYING file. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "common.h" |  | ||||||
| #include "hash.h" |  | ||||||
|  |  | ||||||
| #if defined(PPC_SHA1) |  | ||||||
| # include "ppc/sha1.h" |  | ||||||
| #else |  | ||||||
| # include "sha1.h" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| struct git_hash_ctx { |  | ||||||
| 	SHA_CTX c; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| git_hash_ctx *git_hash_new_ctx(void) |  | ||||||
| { |  | ||||||
| 	git_hash_ctx *ctx = git__malloc(sizeof(*ctx)); |  | ||||||
|  |  | ||||||
| 	if (!ctx) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	SHA1_Init(&ctx->c); |  | ||||||
|  |  | ||||||
| 	return ctx; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void git_hash_free_ctx(git_hash_ctx *ctx) |  | ||||||
| { |  | ||||||
| 	git__free(ctx); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void git_hash_init(git_hash_ctx *ctx) |  | ||||||
| { |  | ||||||
| 	assert(ctx); |  | ||||||
| 	SHA1_Init(&ctx->c); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) |  | ||||||
| { |  | ||||||
| 	assert(ctx); |  | ||||||
| 	SHA1_Update(&ctx->c, data, len); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void git_hash_final(git_oid *out, git_hash_ctx *ctx) |  | ||||||
| { |  | ||||||
| 	assert(ctx); |  | ||||||
| 	SHA1_Final(out->id, &ctx->c); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void git_hash_buf(git_oid *out, const void *data, size_t len) |  | ||||||
| { |  | ||||||
| 	SHA_CTX c; |  | ||||||
|  |  | ||||||
| 	SHA1_Init(&c); |  | ||||||
| 	SHA1_Update(&c, data, len); |  | ||||||
| 	SHA1_Final(out->id, &c); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void git_hash_vec(git_oid *out, git_buf_vec *vec, size_t n) |  | ||||||
| { |  | ||||||
| 	SHA_CTX c; |  | ||||||
| 	size_t i; |  | ||||||
|  |  | ||||||
| 	SHA1_Init(&c); |  | ||||||
| 	for (i = 0; i < n; i++) |  | ||||||
| 		SHA1_Update(&c, vec[i].data, vec[i].len); |  | ||||||
| 	SHA1_Final(out->id, &c); |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user