mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	Merge pull request #3078 from sahildua2305/remove-gpl-samples
Remove GPL Licensed Samples
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); | ||||
| } | ||||
							
								
								
									
										257
									
								
								samples/C/custom_extensions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								samples/C/custom_extensions.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| /* Copyright (c) 2014, Google Inc. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||||
|  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||||
|  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||||
|  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | ||||
|  | ||||
| #include <openssl/ssl.h> | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include <openssl/bytestring.h> | ||||
| #include <openssl/err.h> | ||||
| #include <openssl/mem.h> | ||||
| #include <openssl/stack.h> | ||||
|  | ||||
| #include "internal.h" | ||||
|  | ||||
|  | ||||
| void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension) { | ||||
|   OPENSSL_free(custom_extension); | ||||
| } | ||||
|  | ||||
| static const SSL_CUSTOM_EXTENSION *custom_ext_find( | ||||
|     STACK_OF(SSL_CUSTOM_EXTENSION) *stack, | ||||
|     unsigned *out_index, uint16_t value) { | ||||
|   size_t i; | ||||
|   for (i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) { | ||||
|     const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i); | ||||
|     if (ext->value == value) { | ||||
|       if (out_index != NULL) { | ||||
|         *out_index = i; | ||||
|       } | ||||
|       return ext; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| /* default_add_callback is used as the |add_callback| when the user doesn't | ||||
|  * provide one. For servers, it does nothing while, for clients, it causes an | ||||
|  * empty extension to be included. */ | ||||
| static int default_add_callback(SSL *ssl, unsigned extension_value, | ||||
|                                 const uint8_t **out, size_t *out_len, | ||||
|                                 int *out_alert_value, void *add_arg) { | ||||
|   if (ssl->server) { | ||||
|     return 0; | ||||
|   } | ||||
|   *out_len = 0; | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { | ||||
|   STACK_OF(SSL_CUSTOM_EXTENSION) *stack = ssl->ctx->client_custom_extensions; | ||||
|   if (ssl->server) { | ||||
|     stack = ssl->ctx->server_custom_extensions; | ||||
|   } | ||||
|  | ||||
|   if (stack == NULL) { | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   size_t i; | ||||
|   for (i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) { | ||||
|     const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i); | ||||
|  | ||||
|     if (ssl->server && | ||||
|         !(ssl->s3->tmp.custom_extensions.received & (1u << i))) { | ||||
|       /* Servers cannot echo extensions that the client didn't send. */ | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     const uint8_t *contents; | ||||
|     size_t contents_len; | ||||
|     int alert = SSL_AD_DECODE_ERROR; | ||||
|     CBB contents_cbb; | ||||
|  | ||||
|     switch (ext->add_callback(ssl, ext->value, &contents, &contents_len, &alert, | ||||
|                               ext->add_arg)) { | ||||
|       case 1: | ||||
|         if (!CBB_add_u16(extensions, ext->value) || | ||||
|             !CBB_add_u16_length_prefixed(extensions, &contents_cbb) || | ||||
|             !CBB_add_bytes(&contents_cbb, contents, contents_len) || | ||||
|             !CBB_flush(extensions)) { | ||||
|           OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | ||||
|           ERR_add_error_dataf("extension: %u", (unsigned) ext->value); | ||||
|           if (ext->free_callback && 0 < contents_len) { | ||||
|             ext->free_callback(ssl, ext->value, contents, ext->add_arg); | ||||
|           } | ||||
|           return 0; | ||||
|         } | ||||
|  | ||||
|         if (ext->free_callback && 0 < contents_len) { | ||||
|           ext->free_callback(ssl, ext->value, contents, ext->add_arg); | ||||
|         } | ||||
|  | ||||
|         if (!ssl->server) { | ||||
|           assert((ssl->s3->tmp.custom_extensions.sent & (1u << i)) == 0); | ||||
|           ssl->s3->tmp.custom_extensions.sent |= (1u << i); | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|       case 0: | ||||
|         break; | ||||
|  | ||||
|       default: | ||||
|         ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); | ||||
|         OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); | ||||
|         ERR_add_error_dataf("extension: %u", (unsigned) ext->value); | ||||
|         return 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| int custom_ext_add_clienthello(SSL *ssl, CBB *extensions) { | ||||
|   return custom_ext_add_hello(ssl, extensions); | ||||
| } | ||||
|  | ||||
| int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, | ||||
|                                  const CBS *extension) { | ||||
|   unsigned index; | ||||
|   const SSL_CUSTOM_EXTENSION *ext = | ||||
|       custom_ext_find(ssl->ctx->client_custom_extensions, &index, value); | ||||
|  | ||||
|   if (/* Unknown extensions are not allowed in a ServerHello. */ | ||||
|       ext == NULL || | ||||
|       /* Also, if we didn't send the extension, that's also unacceptable. */ | ||||
|       !(ssl->s3->tmp.custom_extensions.sent & (1u << index))) { | ||||
|     OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); | ||||
|     ERR_add_error_dataf("extension: %u", (unsigned)value); | ||||
|     *out_alert = SSL_AD_DECODE_ERROR; | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if (ext->parse_callback != NULL && | ||||
|       !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension), | ||||
|                            out_alert, ext->parse_arg)) { | ||||
|     OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); | ||||
|     ERR_add_error_dataf("extension: %u", (unsigned)ext->value); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, | ||||
|                                  const CBS *extension) { | ||||
|   unsigned index; | ||||
|   const SSL_CUSTOM_EXTENSION *ext = | ||||
|       custom_ext_find(ssl->ctx->server_custom_extensions, &index, value); | ||||
|  | ||||
|   if (ext == NULL) { | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   assert((ssl->s3->tmp.custom_extensions.received & (1u << index)) == 0); | ||||
|   ssl->s3->tmp.custom_extensions.received |= (1u << index); | ||||
|  | ||||
|   if (ext->parse_callback && | ||||
|       !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension), | ||||
|                            out_alert, ext->parse_arg)) { | ||||
|     OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR); | ||||
|     ERR_add_error_dataf("extension: %u", (unsigned)ext->value); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| int custom_ext_add_serverhello(SSL *ssl, CBB *extensions) { | ||||
|   return custom_ext_add_hello(ssl, extensions); | ||||
| } | ||||
|  | ||||
| /* MAX_NUM_CUSTOM_EXTENSIONS is the maximum number of custom extensions that | ||||
|  * can be set on an |SSL_CTX|. It's determined by the size of the bitset used | ||||
|  * to track when an extension has been sent. */ | ||||
| #define MAX_NUM_CUSTOM_EXTENSIONS \ | ||||
|   (sizeof(((struct ssl3_state_st *)NULL)->tmp.custom_extensions.sent) * 8) | ||||
|  | ||||
| static int custom_ext_append(STACK_OF(SSL_CUSTOM_EXTENSION) **stack, | ||||
|                              unsigned extension_value, | ||||
|                              SSL_custom_ext_add_cb add_cb, | ||||
|                              SSL_custom_ext_free_cb free_cb, void *add_arg, | ||||
|                              SSL_custom_ext_parse_cb parse_cb, | ||||
|                              void *parse_arg) { | ||||
|   if (add_cb == NULL || | ||||
|       0xffff < extension_value || | ||||
|       SSL_extension_supported(extension_value) || | ||||
|       /* Specifying a free callback without an add callback is nonsensical | ||||
|        * and an error. */ | ||||
|       (*stack != NULL && | ||||
|        (MAX_NUM_CUSTOM_EXTENSIONS <= sk_SSL_CUSTOM_EXTENSION_num(*stack) || | ||||
|         custom_ext_find(*stack, NULL, extension_value) != NULL))) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   SSL_CUSTOM_EXTENSION *ext = OPENSSL_malloc(sizeof(SSL_CUSTOM_EXTENSION)); | ||||
|   if (ext == NULL) { | ||||
|     return 0; | ||||
|   } | ||||
|   ext->add_callback = add_cb; | ||||
|   ext->add_arg = add_arg; | ||||
|   ext->free_callback = free_cb; | ||||
|   ext->parse_callback = parse_cb; | ||||
|   ext->parse_arg = parse_arg; | ||||
|   ext->value = extension_value; | ||||
|  | ||||
|   if (*stack == NULL) { | ||||
|     *stack = sk_SSL_CUSTOM_EXTENSION_new_null(); | ||||
|     if (*stack == NULL) { | ||||
|       SSL_CUSTOM_EXTENSION_free(ext); | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (!sk_SSL_CUSTOM_EXTENSION_push(*stack, ext)) { | ||||
|     SSL_CUSTOM_EXTENSION_free(ext); | ||||
|     if (sk_SSL_CUSTOM_EXTENSION_num(*stack) == 0) { | ||||
|       sk_SSL_CUSTOM_EXTENSION_free(*stack); | ||||
|       *stack = NULL; | ||||
|     } | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned extension_value, | ||||
|                                   SSL_custom_ext_add_cb add_cb, | ||||
|                                   SSL_custom_ext_free_cb free_cb, void *add_arg, | ||||
|                                   SSL_custom_ext_parse_cb parse_cb, | ||||
|                                   void *parse_arg) { | ||||
|   return custom_ext_append(&ctx->client_custom_extensions, extension_value, | ||||
|                            add_cb ? add_cb : default_add_callback, free_cb, | ||||
|                            add_arg, parse_cb, parse_arg); | ||||
| } | ||||
|  | ||||
| int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned extension_value, | ||||
|                                   SSL_custom_ext_add_cb add_cb, | ||||
|                                   SSL_custom_ext_free_cb free_cb, void *add_arg, | ||||
|                                   SSL_custom_ext_parse_cb parse_cb, | ||||
|                                   void *parse_arg) { | ||||
|   return custom_ext_append(&ctx->server_custom_extensions, extension_value, | ||||
|                            add_cb ? add_cb : default_add_callback, free_cb, | ||||
|                            add_arg, parse_cb, parse_arg); | ||||
| } | ||||
							
								
								
									
										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