#include "quote.h"
#include "hashmap.h"
#include "string-list.h"
+#include "utf8.h"
struct config_source {
struct config_source *prev;
static int config_buf_ungetc(int c, struct config_source *conf)
{
- if (conf->u.buf.pos > 0)
- return conf->u.buf.buf[--conf->u.buf.pos];
+ if (conf->u.buf.pos > 0) {
+ conf->u.buf.pos--;
+ if (conf->u.buf.buf[conf->u.buf.pos] != c)
+ die("BUG: config_buf can only ungetc the same character");
+ return c;
+ }
return EOF;
}
/* DOS like systems */
c = cf->do_fgetc(cf);
if (c != '\n') {
- cf->do_ungetc(c, cf);
+ if (c != EOF)
+ cf->do_ungetc(c, cf);
c = '\r';
}
}
struct strbuf *var = &cf->var;
/* U+FEFF Byte Order Mark in UTF8 */
- static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
- const unsigned char *bomptr = utf8_bom;
+ const char *bomptr = utf8_bom;
for (;;) {
int c = get_next_char();
/* We are at the file beginning; skip UTF8-encoded BOM
* if present. Sane editors won't put this in on their
* own, but e.g. Windows Notepad will do it happily. */
- if ((unsigned char) c == *bomptr) {
+ if (c == (*bomptr & 0377)) {
bomptr++;
continue;
} else {
int git_config_early(config_fn_t fn, void *data, const char *repo_config)
{
int ret = 0, found = 0;
- char *xdg_config = NULL;
- char *user_config = NULL;
-
- home_config_paths(&user_config, &xdg_config, "config");
+ char *xdg_config = xdg_config_home("config");
+ char *user_config = expand_user_path("~/.gitconfig");
if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
ret += git_config_from_file(fn, git_etc_gitconfig(),
string_list_init(&e->value_list, 1);
hashmap_add(&cs->config_hash, e);
}
- si = string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
+ si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
l_item = &cs->list.items[cs->list.nr++];
int ret;
struct lock_file *lock = NULL;
char *filename_buf = NULL;
+ char *contents = NULL;
+ size_t contents_sz;
/* parse-key returns negative; flip the sign to feed exit(3) */
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
goto write_err_out;
} else {
struct stat st;
- char *contents;
- size_t contents_sz, copy_begin, copy_end;
+ size_t copy_begin, copy_end;
int i, new_line = 0;
if (value_regex == NULL)
fstat(in_fd, &st);
contents_sz = xsize_t(st.st_size);
- contents = xmmap(NULL, contents_sz, PROT_READ,
- MAP_PRIVATE, in_fd, 0);
+ contents = xmmap_gently(NULL, contents_sz, PROT_READ,
+ MAP_PRIVATE, in_fd, 0);
+ if (contents == MAP_FAILED) {
+ if (errno == ENODEV && S_ISDIR(st.st_mode))
+ errno = EISDIR;
+ error("unable to mmap '%s': %s",
+ config_filename, strerror(errno));
+ ret = CONFIG_INVALID_FILE;
+ contents = NULL;
+ goto out_free;
+ }
close(in_fd);
if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) {
contents_sz - copy_begin) <
contents_sz - copy_begin)
goto write_err_out;
-
- munmap(contents, contents_sz);
}
if (commit_lock_file(lock) < 0) {
if (lock)
rollback_lock_file(lock);
free(filename_buf);
+ if (contents)
+ munmap(contents, contents_sz);
return ret;
write_err_out:
#define _FILE_OFFSET_BITS 64
+
+/* Derived from Linux "Features Test Macro" header
+ * Convenience macros to test the versions of gcc (or
+ * a compatible compiler).
+ * Use them like this:
+ * #if GIT_GNUC_PREREQ (2,8)
+ * ... code requiring gcc 2.8 or later ...
+ * #endif
+*/
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define GIT_GNUC_PREREQ(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+ #define GIT_GNUC_PREREQ(maj, min) 0
+#endif
+
+
#ifndef FLEX_ARRAY
/*
* See if our compiler is known to support flexible array members.
#endif
#endif
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+/*
+ * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler. This can be used in an expression: its value is "0".
+ *
+ * Example:
+ * #define foo_to_char(foo) \
+ * ((char *)(foo) \
+ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
+ */
+#define BUILD_ASSERT_OR_ZERO(cond) \
+ (sizeof(char [1 - 2*!(cond)]) - 1)
+
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+# if GIT_GNUC_PREREQ(3, 1)
+ /* &arr[0] degrades to a pointer: a different type from an array */
+# define BARF_UNLESS_AN_ARRAY(arr) \
+ BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(__typeof__(arr), \
+ __typeof__(&(arr)[0])))
+# else
+# define BARF_UNLESS_AN_ARRAY(arr) 0
+# endif
+#endif
+/*
+ * ARRAY_SIZE - get the number of elements in a visible array
+ * <at> x: the array whose size you want.
+ *
+ * This does not work on pointers, or arrays declared as [], or
+ * function parameters. With correct compiler support, such usage
+ * will cause a build error (see the build_assert_or_zero macro).
+ */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]) + BARF_UNLESS_AN_ARRAY(x))
+
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
#define maximum_signed_value_of_type(a) \
# endif
#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
!defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
- !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__)
+ !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__) && \
+ !defined(__CYGWIN__)
#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
#endif
#else
#include <poll.h>
#endif
+#ifdef HAVE_BSD_SYSCTL
+#include <sys/sysctl.h>
+#endif
#if defined(__MINGW32__)
/* pull in Windows compatibility stuff */
typedef long intptr_t;
typedef unsigned long uintptr_t;
#endif
-#if defined(__CYGWIN__)
-#undef _XOPEN_SOURCE
-#include <grp.h>
-#define _XOPEN_SOURCE 600
-#else
#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
#include <grp.h>
#define _ALL_SOURCE 1
#endif
-#endif
/* used on Mac OS X */
#ifdef PRECOMPOSE_UNICODE
#endif
#ifndef NO_OPENSSL
+#ifdef __APPLE__
+#define __AVAILABILITY_MACROS_USES_AVAILABILITY 0
+#include <AvailabilityMacros.h>
+#undef DEPRECATED_ATTRIBUTE
+#define DEPRECATED_ATTRIBUTE
+#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
+#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
+#ifdef NO_HMAC_CTX_CLEANUP
+#define HMAC_CTX_cleanup HMAC_cleanup
+#endif
#endif
/* On most systems <netdb.h> would have given us this, but
#define on_disk_bytes(st) ((st).st_blocks * 512)
#endif
+#ifdef NEEDS_MODE_TRANSLATION
+#undef S_IFMT
+#undef S_IFREG
+#undef S_IFDIR
+#undef S_IFLNK
+#undef S_IFBLK
+#undef S_IFCHR
+#undef S_IFIFO
+#undef S_IFSOCK
+#define S_IFMT 0170000
+#define S_IFREG 0100000
+#define S_IFDIR 0040000
+#define S_IFLNK 0120000
+#define S_IFBLK 0060000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_IFSOCK 0140000
+#ifdef stat
+#undef stat
+#endif
+#define stat(path, buf) git_stat(path, buf)
+extern int git_stat(const char *, struct stat *);
+#ifdef fstat
+#undef fstat
+#endif
+#define fstat(fd, buf) git_fstat(fd, buf)
+extern int git_fstat(int, struct stat *);
+#ifdef lstat
+#undef lstat
+#endif
+#define lstat(path, buf) git_lstat(path, buf)
+extern int git_lstat(const char *, struct stat *);
+#endif
+
#define DEFAULT_PACKED_GIT_LIMIT \
((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
extern void *xrealloc(void *ptr, size_t size);
extern void *xcalloc(size_t nmemb, size_t size);
extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
+ extern void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_t offset);
extern ssize_t xread(int fd, void *buf, size_t len);
extern ssize_t xwrite(int fd, const void *buf, size_t len);
extern ssize_t xpread(int fd, void *buf, size_t len, off_t offset);
#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))
+static inline char *xstrdup_or_null(const char *str)
+{
+ return str ? xstrdup(str) : NULL;
+}
+
static inline size_t xsize_t(off_t len)
{
if (len > (size_t) len)
}
/* in ctype.c, for kwset users */
-extern const char tolower_trans_tbl[256];
+extern const unsigned char tolower_trans_tbl[256];
/* Sane ctype - no locale, and works with signed chars */
#undef isascii
#define gmtime_r git_gmtime_r
#endif
+#if !defined(USE_PARENS_AROUND_GETTEXT_N) && defined(__GNUC__)
+#define USE_PARENS_AROUND_GETTEXT_N 1
+#endif
+
+#ifndef SHELL_PATH
+# define SHELL_PATH "/bin/sh"
+#endif
+
#endif
alias = index_file_exists(istate, ce->name, ce_namelen(ce), ignore_case);
if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {
/* Nothing changed, really */
- free(ce);
if (!S_ISGITLINK(alias->ce_mode))
ce_mark_uptodate(alias);
alias->ce_flags |= CE_ADDED;
+
+ free(ce);
return 0;
}
if (!intent_only) {
- if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT))
+ if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT)) {
+ free(ce);
return error("unable to index file %s", path);
+ }
} else
set_object_name_for_intent_to_add_entry(ce);
ce->ce_mode == alias->ce_mode);
if (pretend)
- ;
- else if (add_index_entry(istate, ce, add_option))
- return error("unable to add %s to index",path);
+ free(ce);
+ else if (add_index_entry(istate, ce, add_option)) {
+ free(ce);
+ return error("unable to add %s to index", path);
+ }
if (verbose && !was_same)
printf("add '%s'\n", path);
return 0;
unsigned int refresh_options)
{
int size, len;
- struct cache_entry *ce;
+ struct cache_entry *ce, *ret;
if (!verify_path(path)) {
error("Invalid path '%s'", path);
ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
- return refresh_cache_entry(ce, refresh_options);
+ ret = refresh_cache_entry(ce, refresh_options);
+ if (ret != ce)
+ free(ce);
+ return ret;
}
int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
return ce;
}
-static void check_ce_order(struct cache_entry *ce, struct cache_entry *next_ce)
+static void check_ce_order(struct index_state *istate)
{
- int name_compare = strcmp(ce->name, next_ce->name);
- if (0 < name_compare)
- die("unordered stage entries in index");
- if (!name_compare) {
- if (!ce_stage(ce))
- die("multiple stage entries for merged file '%s'",
- ce->name);
- if (ce_stage(ce) > ce_stage(next_ce))
- die("unordered stage entries for '%s'",
- ce->name);
+ unsigned int i;
+
+ for (i = 1; i < istate->cache_nr; i++) {
+ struct cache_entry *ce = istate->cache[i - 1];
+ struct cache_entry *next_ce = istate->cache[i];
+ int name_compare = strcmp(ce->name, next_ce->name);
+
+ if (0 < name_compare)
+ die("unordered stage entries in index");
+ if (!name_compare) {
+ if (!ce_stage(ce))
+ die("multiple stage entries for merged file '%s'",
+ ce->name);
+ if (ce_stage(ce) > ce_stage(next_ce))
+ die("unordered stage entries for '%s'",
+ ce->name);
+ }
}
}
if (mmap_size < sizeof(struct cache_header) + 20)
die("index file smaller than expected");
- mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (mmap == MAP_FAILED)
die_errno("unable to map index file");
close(fd);
ce = create_from_disk(disk_ce, &consumed, previous_name);
set_index_entry(istate, i, ce);
- if (i > 0)
- check_ce_order(istate->cache[i - 1], ce);
-
src_offset += consumed;
}
strbuf_release(&previous_name_buf);
ret = do_read_index(istate, path, 0);
split_index = istate->split_index;
- if (!split_index)
- return ret;
-
- if (is_null_sha1(split_index->base_sha1))
+ if (!split_index || is_null_sha1(split_index->base_sha1)) {
+ check_ce_order(istate);
return ret;
+ }
if (split_index->base)
discard_index(split_index->base);
sha1_to_hex(split_index->base_sha1)),
sha1_to_hex(split_index->base->sha1));
merge_base_index(istate);
+ check_ce_order(istate);
return ret;
}
(uintmax_t)length, (uintmax_t)limit);
}
- void *xmmap(void *start, size_t length,
- int prot, int flags, int fd, off_t offset)
+ void *xmmap_gently(void *start, size_t length,
+ int prot, int flags, int fd, off_t offset)
{
void *ret;
return NULL;
release_pack_memory(length);
ret = mmap(start, length, prot, flags, fd, offset);
- if (ret == MAP_FAILED)
- die_errno("Out of memory? mmap failed");
}
return ret;
}
+ void *xmmap(void *start, size_t length,
+ int prot, int flags, int fd, off_t offset)
+ {
+ void *ret = xmmap_gently(start, length, prot, flags, fd, offset);
+ if (ret == MAP_FAILED)
+ die_errno("mmap failed");
+ return ret;
+ }
+
void close_pack_windows(struct packed_git *p)
{
while (p->windows) {
if (!report_garbage)
return;
- sort_string_list(list);
+ string_list_sort(list);
for (i = 0; i < list->nr; i++) {
const char *path = list->items[i].string;
* answer, as it may have been deleted since the index was
* loaded!
*/
- if (!is_pack_valid(p)) {
- warning("packfile %s cannot be accessed", p->pack_name);
+ if (!is_pack_valid(p))
return 0;
- }
e->offset = offset;
e->p = p;
hashcpy(e->sha1, sha1);
}
/* Set it up */
- memset(&stream, 0, sizeof(stream));
git_deflate_init(&stream, zlib_compression_level);
stream.next_out = compressed;
stream.avail_out = sizeof(compressed);
static int freshen_packed_object(const unsigned char *sha1)
{
struct pack_entry e;
- return find_pack_entry(sha1, &e) && freshen_file(e.p->pack_name);
+ if (!find_pack_entry(sha1, &e))
+ return 0;
+ if (e.p->freshened)
+ return 1;
+ if (!freshen_file(e.p->pack_name))
+ return 0;
+ e.p->freshened = 1;
+ return 1;
}
-int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
+int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1)
{
- unsigned char sha1[20];
char hdr[32];
int hdrlen;
* it out into .git/objects/??/?{38} file.
*/
write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
- if (returnsha1)
- hashcpy(returnsha1, sha1);
- if (freshen_loose_object(sha1) || freshen_packed_object(sha1))
+ if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
return 0;
return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
}
+int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type,
+ unsigned char *sha1, unsigned flags)
+{
+ char *header;
+ int hdrlen, status = 0;
+
+ /* type string, SP, %lu of the length plus NUL must fit this */
+ header = xmalloc(strlen(type) + 32);
+ write_sha1_file_prepare(buf, len, type, sha1, header, &hdrlen);
+
+ if (!(flags & HASH_WRITE_OBJECT))
+ goto cleanup;
+ if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
+ goto cleanup;
+ status = write_loose_object(sha1, header, hdrlen, buf, len, 0);
+
+cleanup:
+ free(header);
+ return status;
+}
+
int force_object_loose(const unsigned char *sha1, time_t mtime)
{
void *buf;
int ret;
if (!size) {
- ret = index_mem(sha1, NULL, size, type, path, flags);
+ ret = index_mem(sha1, "", size, type, path, flags);
} else if (size <= SMALL_FILE_SIZE) {
char *buf = xmalloc(size);
if (size == read_in_full(fd, buf, size))
return r;
}
-int for_each_loose_file_in_objdir(const char *path,
+int for_each_loose_file_in_objdir_buf(struct strbuf *path,
each_loose_object_fn obj_cb,
each_loose_cruft_fn cruft_cb,
each_loose_subdir_fn subdir_cb,
void *data)
{
- struct strbuf buf = STRBUF_INIT;
- size_t baselen;
+ size_t baselen = path->len;
int r = 0;
int i;
- strbuf_addstr(&buf, path);
- strbuf_addch(&buf, '/');
- baselen = buf.len;
-
for (i = 0; i < 256; i++) {
- strbuf_addf(&buf, "%02x", i);
- r = for_each_file_in_obj_subdir(i, &buf, obj_cb, cruft_cb,
+ strbuf_addf(path, "/%02x", i);
+ r = for_each_file_in_obj_subdir(i, path, obj_cb, cruft_cb,
subdir_cb, data);
- strbuf_setlen(&buf, baselen);
+ strbuf_setlen(path, baselen);
if (r)
break;
}
+ return r;
+}
+
+int for_each_loose_file_in_objdir(const char *path,
+ each_loose_object_fn obj_cb,
+ each_loose_cruft_fn cruft_cb,
+ each_loose_subdir_fn subdir_cb,
+ void *data)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int r;
+
+ strbuf_addstr(&buf, path);
+ r = for_each_loose_file_in_objdir_buf(&buf, obj_cb, cruft_cb,
+ subdir_cb, data);
strbuf_release(&buf);
+
return r;
}
void *vdata)
{
struct loose_alt_odb_data *data = vdata;
- return for_each_loose_file_in_objdir(alt->base,
- data->cb, NULL, NULL,
- data->data);
+ struct strbuf buf = STRBUF_INIT;
+ int r;
+
+ /* copy base not including trailing '/' */
+ strbuf_add(&buf, alt->base, alt->name - alt->base - 1);
+ r = for_each_loose_file_in_objdir_buf(&buf,
+ data->cb, NULL, NULL,
+ data->data);
+ strbuf_release(&buf);
+ return r;
}
-int for_each_loose_object(each_loose_object_fn cb, void *data)
+int for_each_loose_object(each_loose_object_fn cb, void *data, unsigned flags)
{
struct loose_alt_odb_data alt;
int r;
if (r)
return r;
+ if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
+ return 0;
+
alt.cb = cb;
alt.data = data;
return foreach_alt_odb(loose_from_alt_odb, &alt);
return r;
}
-int for_each_packed_object(each_packed_object_fn cb, void *data)
+int for_each_packed_object(each_packed_object_fn cb, void *data, unsigned flags)
{
struct packed_git *p;
int r = 0;
prepare_packed_git();
for (p = packed_git; p; p = p->next) {
+ if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
+ continue;
r = for_each_object_in_pack(p, cb, data);
if (r)
break;