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