git/wrapper.c

693 lines
15 KiB
C
Raw Normal View History

Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
/*
* Various trivial helper wrappers around standard functions
*/
#include "cache.h"
#include "config.h"
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
static void do_nothing(size_t size)
{
}
static void (*try_to_free_routine)(size_t size) = do_nothing;
static int memory_limit_check(size_t size, int gentle)
{
static size_t limit = 0;
if (!limit) {
limit = git_env_ulong("GIT_ALLOC_LIMIT", 0);
if (!limit)
limit = SIZE_MAX;
}
if (size > limit) {
if (gentle) {
error("attempting to allocate %"PRIuMAX" over limit %"PRIuMAX,
(uintmax_t)size, (uintmax_t)limit);
return -1;
} else
die("attempting to allocate %"PRIuMAX" over limit %"PRIuMAX,
(uintmax_t)size, (uintmax_t)limit);
}
return 0;
}
try_to_free_t set_try_to_free_routine(try_to_free_t routine)
{
try_to_free_t old = try_to_free_routine;
if (!routine)
routine = do_nothing;
try_to_free_routine = routine;
return old;
}
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
char *xstrdup(const char *str)
{
char *ret = strdup(str);
if (!ret) {
try_to_free_routine(strlen(str) + 1);
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
ret = strdup(str);
if (!ret)
die("Out of memory, strdup failed");
}
return ret;
}
static void *do_xmalloc(size_t size, int gentle)
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
{
void *ret;
if (memory_limit_check(size, gentle))
return NULL;
ret = malloc(size);
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
if (!ret && !size)
ret = malloc(1);
if (!ret) {
try_to_free_routine(size);
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
ret = malloc(size);
if (!ret && !size)
ret = malloc(1);
if (!ret) {
if (!gentle)
die("Out of memory, malloc failed (tried to allocate %lu bytes)",
(unsigned long)size);
else {
error("Out of memory, malloc failed (tried to allocate %lu bytes)",
(unsigned long)size);
return NULL;
}
}
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
}
#ifdef XMALLOC_POISON
memset(ret, 0xA5, size);
#endif
return ret;
}
void *xmalloc(size_t size)
{
return do_xmalloc(size, 0);
}
static void *do_xmallocz(size_t size, int gentle)
{
void *ret;
if (unsigned_add_overflows(size, 1)) {
if (gentle) {
error("Data too large to fit into virtual memory space.");
return NULL;
} else
die("Data too large to fit into virtual memory space.");
}
ret = do_xmalloc(size + 1, gentle);
if (ret)
((char*)ret)[size] = 0;
return ret;
}
void *xmallocz(size_t size)
{
return do_xmallocz(size, 0);
}
void *xmallocz_gently(size_t size)
{
return do_xmallocz(size, 1);
}
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
/*
* xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
* "data" to the allocated memory, zero terminates the allocated memory,
* and returns a pointer to the allocated memory. If the allocation fails,
* the program dies.
*/
void *xmemdupz(const void *data, size_t len)
{
return memcpy(xmallocz(len), data, len);
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
}
char *xstrndup(const char *str, size_t len)
{
char *p = memchr(str, '\0', len);
return xmemdupz(str, p ? p - str : len);
}
void *xrealloc(void *ptr, size_t size)
{
void *ret;
memory_limit_check(size, 0);
ret = realloc(ptr, size);
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
if (!ret && !size)
ret = realloc(ptr, 1);
if (!ret) {
try_to_free_routine(size);
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
ret = realloc(ptr, size);
if (!ret && !size)
ret = realloc(ptr, 1);
if (!ret)
die("Out of memory, realloc failed");
}
return ret;
}
void *xcalloc(size_t nmemb, size_t size)
{
void *ret;
if (unsigned_mult_overflows(nmemb, size))
die("data too large to fit into virtual memory space");
memory_limit_check(size * nmemb, 0);
ret = calloc(nmemb, size);
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
if (!ret && (!nmemb || !size))
ret = calloc(1, 1);
if (!ret) {
try_to_free_routine(nmemb * size);
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
ret = calloc(nmemb, size);
if (!ret && (!nmemb || !size))
ret = calloc(1, 1);
if (!ret)
die("Out of memory, calloc failed");
}
return ret;
}
xread, xwrite: limit size of IO to 8MB Checking out 2GB or more through an external filter (see test) fails on Mac OS X 10.8.4 (12E55) for a 64-bit executable with: error: read from external filter cat failed error: cannot feed the input to external filter cat error: cat died of signal 13 error: external filter cat failed 141 error: external filter cat failed The reason is that read() immediately returns with EINVAL when asked to read more than 2GB. According to POSIX [1], if the value of nbyte passed to read() is greater than SSIZE_MAX, the result is implementation-defined. The write function has the same restriction [2]. Since OS X still supports running 32-bit executables, the 32-bit limit (SSIZE_MAX = INT_MAX = 2GB - 1) seems to be also imposed on 64-bit executables under certain conditions. For write, the problem has been addressed earlier [6c642a]. Address the problem for read() and write() differently, by limiting size of IO chunks unconditionally on all platforms in xread() and xwrite(). Large chunks only cause problems, like causing latencies when killing the process, even if OS X was not buggy. Doing IO in reasonably sized smaller chunks should have no negative impact on performance. The compat wrapper clipped_write() introduced earlier [6c642a] is not needed anymore. It will be reverted in a separate commit. The new test catches read and write problems. Note that 'git add' exits with 0 even if it prints filtering errors to stderr. The test, therefore, checks stderr. 'git add' should probably be changed (sometime in another commit) to exit with nonzero if filtering fails. The test could then be changed to use test_must_fail. Thanks to the following people for suggestions and testing: Johannes Sixt <j6t@kdbg.org> John Keeping <john@keeping.me.uk> Jonathan Nieder <jrnieder@gmail.com> Kyle J. McKay <mackyle@gmail.com> Linus Torvalds <torvalds@linux-foundation.org> Torsten Bögershausen <tboegi@web.de> [1] http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html [2] http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html [6c642a] commit 6c642a878688adf46b226903858b53e2d31ac5c3 compate/clipped-write.c: large write(2) fails on Mac OS X/XNU Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-20 14:43:54 +08:00
/*
* Limit size of IO chunks, because huge chunks only cause pain. OS X
* 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
* the absence of bugs, large chunks can result in bad latencies when
xread, xwrite: limit size of IO to 8MB Checking out 2GB or more through an external filter (see test) fails on Mac OS X 10.8.4 (12E55) for a 64-bit executable with: error: read from external filter cat failed error: cannot feed the input to external filter cat error: cat died of signal 13 error: external filter cat failed 141 error: external filter cat failed The reason is that read() immediately returns with EINVAL when asked to read more than 2GB. According to POSIX [1], if the value of nbyte passed to read() is greater than SSIZE_MAX, the result is implementation-defined. The write function has the same restriction [2]. Since OS X still supports running 32-bit executables, the 32-bit limit (SSIZE_MAX = INT_MAX = 2GB - 1) seems to be also imposed on 64-bit executables under certain conditions. For write, the problem has been addressed earlier [6c642a]. Address the problem for read() and write() differently, by limiting size of IO chunks unconditionally on all platforms in xread() and xwrite(). Large chunks only cause problems, like causing latencies when killing the process, even if OS X was not buggy. Doing IO in reasonably sized smaller chunks should have no negative impact on performance. The compat wrapper clipped_write() introduced earlier [6c642a] is not needed anymore. It will be reverted in a separate commit. The new test catches read and write problems. Note that 'git add' exits with 0 even if it prints filtering errors to stderr. The test, therefore, checks stderr. 'git add' should probably be changed (sometime in another commit) to exit with nonzero if filtering fails. The test could then be changed to use test_must_fail. Thanks to the following people for suggestions and testing: Johannes Sixt <j6t@kdbg.org> John Keeping <john@keeping.me.uk> Jonathan Nieder <jrnieder@gmail.com> Kyle J. McKay <mackyle@gmail.com> Linus Torvalds <torvalds@linux-foundation.org> Torsten Bögershausen <tboegi@web.de> [1] http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html [2] http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html [6c642a] commit 6c642a878688adf46b226903858b53e2d31ac5c3 compate/clipped-write.c: large write(2) fails on Mac OS X/XNU Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-20 14:43:54 +08:00
* you decide to kill the process.
*
* We pick 8 MiB as our default, but if the platform defines SSIZE_MAX
* that is smaller than that, clip it to SSIZE_MAX, as a call to
* read(2) or write(2) larger than that is allowed to fail. As the last
* resort, we allow a port to pass via CFLAGS e.g. "-DMAX_IO_SIZE=value"
* to override this, if the definition of SSIZE_MAX given by the platform
* is broken.
xread, xwrite: limit size of IO to 8MB Checking out 2GB or more through an external filter (see test) fails on Mac OS X 10.8.4 (12E55) for a 64-bit executable with: error: read from external filter cat failed error: cannot feed the input to external filter cat error: cat died of signal 13 error: external filter cat failed 141 error: external filter cat failed The reason is that read() immediately returns with EINVAL when asked to read more than 2GB. According to POSIX [1], if the value of nbyte passed to read() is greater than SSIZE_MAX, the result is implementation-defined. The write function has the same restriction [2]. Since OS X still supports running 32-bit executables, the 32-bit limit (SSIZE_MAX = INT_MAX = 2GB - 1) seems to be also imposed on 64-bit executables under certain conditions. For write, the problem has been addressed earlier [6c642a]. Address the problem for read() and write() differently, by limiting size of IO chunks unconditionally on all platforms in xread() and xwrite(). Large chunks only cause problems, like causing latencies when killing the process, even if OS X was not buggy. Doing IO in reasonably sized smaller chunks should have no negative impact on performance. The compat wrapper clipped_write() introduced earlier [6c642a] is not needed anymore. It will be reverted in a separate commit. The new test catches read and write problems. Note that 'git add' exits with 0 even if it prints filtering errors to stderr. The test, therefore, checks stderr. 'git add' should probably be changed (sometime in another commit) to exit with nonzero if filtering fails. The test could then be changed to use test_must_fail. Thanks to the following people for suggestions and testing: Johannes Sixt <j6t@kdbg.org> John Keeping <john@keeping.me.uk> Jonathan Nieder <jrnieder@gmail.com> Kyle J. McKay <mackyle@gmail.com> Linus Torvalds <torvalds@linux-foundation.org> Torsten Bögershausen <tboegi@web.de> [1] http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html [2] http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html [6c642a] commit 6c642a878688adf46b226903858b53e2d31ac5c3 compate/clipped-write.c: large write(2) fails on Mac OS X/XNU Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-20 14:43:54 +08:00
*/
#ifndef MAX_IO_SIZE
# define MAX_IO_SIZE_DEFAULT (8*1024*1024)
# if defined(SSIZE_MAX) && (SSIZE_MAX < MAX_IO_SIZE_DEFAULT)
# define MAX_IO_SIZE SSIZE_MAX
# else
# define MAX_IO_SIZE MAX_IO_SIZE_DEFAULT
# endif
#endif
xread, xwrite: limit size of IO to 8MB Checking out 2GB or more through an external filter (see test) fails on Mac OS X 10.8.4 (12E55) for a 64-bit executable with: error: read from external filter cat failed error: cannot feed the input to external filter cat error: cat died of signal 13 error: external filter cat failed 141 error: external filter cat failed The reason is that read() immediately returns with EINVAL when asked to read more than 2GB. According to POSIX [1], if the value of nbyte passed to read() is greater than SSIZE_MAX, the result is implementation-defined. The write function has the same restriction [2]. Since OS X still supports running 32-bit executables, the 32-bit limit (SSIZE_MAX = INT_MAX = 2GB - 1) seems to be also imposed on 64-bit executables under certain conditions. For write, the problem has been addressed earlier [6c642a]. Address the problem for read() and write() differently, by limiting size of IO chunks unconditionally on all platforms in xread() and xwrite(). Large chunks only cause problems, like causing latencies when killing the process, even if OS X was not buggy. Doing IO in reasonably sized smaller chunks should have no negative impact on performance. The compat wrapper clipped_write() introduced earlier [6c642a] is not needed anymore. It will be reverted in a separate commit. The new test catches read and write problems. Note that 'git add' exits with 0 even if it prints filtering errors to stderr. The test, therefore, checks stderr. 'git add' should probably be changed (sometime in another commit) to exit with nonzero if filtering fails. The test could then be changed to use test_must_fail. Thanks to the following people for suggestions and testing: Johannes Sixt <j6t@kdbg.org> John Keeping <john@keeping.me.uk> Jonathan Nieder <jrnieder@gmail.com> Kyle J. McKay <mackyle@gmail.com> Linus Torvalds <torvalds@linux-foundation.org> Torsten Bögershausen <tboegi@web.de> [1] http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html [2] http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html [6c642a] commit 6c642a878688adf46b226903858b53e2d31ac5c3 compate/clipped-write.c: large write(2) fails on Mac OS X/XNU Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-20 14:43:54 +08:00
/**
* xopen() is the same as open(), but it die()s if the open() fails.
*/
int xopen(const char *path, int oflag, ...)
{
mode_t mode = 0;
va_list ap;
/*
* va_arg() will have undefined behavior if the specified type is not
* compatible with the argument type. Since integers are promoted to
* ints, we fetch the next argument as an int, and then cast it to a
* mode_t to avoid undefined behavior.
*/
va_start(ap, oflag);
if (oflag & O_CREAT)
mode = va_arg(ap, int);
va_end(ap);
for (;;) {
int fd = open(path, oflag, mode);
if (fd >= 0)
return fd;
if (errno == EINTR)
continue;
if ((oflag & O_RDWR) == O_RDWR)
die_errno(_("could not open '%s' for reading and writing"), path);
else if ((oflag & O_WRONLY) == O_WRONLY)
die_errno(_("could not open '%s' for writing"), path);
else
die_errno(_("could not open '%s' for reading"), path);
}
}
static int handle_nonblock(int fd, short poll_events, int err)
{
struct pollfd pfd;
if (err != EAGAIN && err != EWOULDBLOCK)
return 0;
pfd.fd = fd;
pfd.events = poll_events;
/*
* no need to check for errors, here;
* a subsequent read/write will detect unrecoverable errors
*/
poll(&pfd, 1, -1);
return 1;
}
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
/*
* xread() is the same a read(), but it automatically restarts read()
* operations with a recoverable error (EAGAIN and EINTR). xread()
* DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
*/
ssize_t xread(int fd, void *buf, size_t len)
{
ssize_t nr;
xread, xwrite: limit size of IO to 8MB Checking out 2GB or more through an external filter (see test) fails on Mac OS X 10.8.4 (12E55) for a 64-bit executable with: error: read from external filter cat failed error: cannot feed the input to external filter cat error: cat died of signal 13 error: external filter cat failed 141 error: external filter cat failed The reason is that read() immediately returns with EINVAL when asked to read more than 2GB. According to POSIX [1], if the value of nbyte passed to read() is greater than SSIZE_MAX, the result is implementation-defined. The write function has the same restriction [2]. Since OS X still supports running 32-bit executables, the 32-bit limit (SSIZE_MAX = INT_MAX = 2GB - 1) seems to be also imposed on 64-bit executables under certain conditions. For write, the problem has been addressed earlier [6c642a]. Address the problem for read() and write() differently, by limiting size of IO chunks unconditionally on all platforms in xread() and xwrite(). Large chunks only cause problems, like causing latencies when killing the process, even if OS X was not buggy. Doing IO in reasonably sized smaller chunks should have no negative impact on performance. The compat wrapper clipped_write() introduced earlier [6c642a] is not needed anymore. It will be reverted in a separate commit. The new test catches read and write problems. Note that 'git add' exits with 0 even if it prints filtering errors to stderr. The test, therefore, checks stderr. 'git add' should probably be changed (sometime in another commit) to exit with nonzero if filtering fails. The test could then be changed to use test_must_fail. Thanks to the following people for suggestions and testing: Johannes Sixt <j6t@kdbg.org> John Keeping <john@keeping.me.uk> Jonathan Nieder <jrnieder@gmail.com> Kyle J. McKay <mackyle@gmail.com> Linus Torvalds <torvalds@linux-foundation.org> Torsten Bögershausen <tboegi@web.de> [1] http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html [2] http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html [6c642a] commit 6c642a878688adf46b226903858b53e2d31ac5c3 compate/clipped-write.c: large write(2) fails on Mac OS X/XNU Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-20 14:43:54 +08:00
if (len > MAX_IO_SIZE)
len = MAX_IO_SIZE;
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
while (1) {
nr = read(fd, buf, len);
if (nr < 0) {
if (errno == EINTR)
continue;
if (handle_nonblock(fd, POLLIN, errno))
continue;
}
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
return nr;
}
}
/*
* xwrite() is the same a write(), but it automatically restarts write()
* operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
* GUARANTEE that "len" bytes is written even if the operation is successful.
*/
ssize_t xwrite(int fd, const void *buf, size_t len)
{
ssize_t nr;
xread, xwrite: limit size of IO to 8MB Checking out 2GB or more through an external filter (see test) fails on Mac OS X 10.8.4 (12E55) for a 64-bit executable with: error: read from external filter cat failed error: cannot feed the input to external filter cat error: cat died of signal 13 error: external filter cat failed 141 error: external filter cat failed The reason is that read() immediately returns with EINVAL when asked to read more than 2GB. According to POSIX [1], if the value of nbyte passed to read() is greater than SSIZE_MAX, the result is implementation-defined. The write function has the same restriction [2]. Since OS X still supports running 32-bit executables, the 32-bit limit (SSIZE_MAX = INT_MAX = 2GB - 1) seems to be also imposed on 64-bit executables under certain conditions. For write, the problem has been addressed earlier [6c642a]. Address the problem for read() and write() differently, by limiting size of IO chunks unconditionally on all platforms in xread() and xwrite(). Large chunks only cause problems, like causing latencies when killing the process, even if OS X was not buggy. Doing IO in reasonably sized smaller chunks should have no negative impact on performance. The compat wrapper clipped_write() introduced earlier [6c642a] is not needed anymore. It will be reverted in a separate commit. The new test catches read and write problems. Note that 'git add' exits with 0 even if it prints filtering errors to stderr. The test, therefore, checks stderr. 'git add' should probably be changed (sometime in another commit) to exit with nonzero if filtering fails. The test could then be changed to use test_must_fail. Thanks to the following people for suggestions and testing: Johannes Sixt <j6t@kdbg.org> John Keeping <john@keeping.me.uk> Jonathan Nieder <jrnieder@gmail.com> Kyle J. McKay <mackyle@gmail.com> Linus Torvalds <torvalds@linux-foundation.org> Torsten Bögershausen <tboegi@web.de> [1] http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html [2] http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html [6c642a] commit 6c642a878688adf46b226903858b53e2d31ac5c3 compate/clipped-write.c: large write(2) fails on Mac OS X/XNU Signed-off-by: Steffen Prohaska <prohaska@zib.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-08-20 14:43:54 +08:00
if (len > MAX_IO_SIZE)
len = MAX_IO_SIZE;
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
while (1) {
nr = write(fd, buf, len);
if (nr < 0) {
if (errno == EINTR)
continue;
if (handle_nonblock(fd, POLLOUT, errno))
continue;
}
return nr;
}
}
/*
* xpread() is the same as pread(), but it automatically restarts pread()
* operations with a recoverable error (EAGAIN and EINTR). xpread() DOES
* NOT GUARANTEE that "len" bytes is read even if the data is available.
*/
ssize_t xpread(int fd, void *buf, size_t len, off_t offset)
{
ssize_t nr;
if (len > MAX_IO_SIZE)
len = MAX_IO_SIZE;
while (1) {
nr = pread(fd, buf, len, offset);
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
continue;
return nr;
}
}
ssize_t read_in_full(int fd, void *buf, size_t count)
{
char *p = buf;
ssize_t total = 0;
while (count > 0) {
ssize_t loaded = xread(fd, p, count);
if (loaded < 0)
return -1;
if (loaded == 0)
return total;
count -= loaded;
p += loaded;
total += loaded;
}
return total;
}
ssize_t write_in_full(int fd, const void *buf, size_t count)
{
const char *p = buf;
ssize_t total = 0;
while (count > 0) {
ssize_t written = xwrite(fd, p, count);
if (written < 0)
return -1;
if (!written) {
errno = ENOSPC;
return -1;
}
count -= written;
p += written;
total += written;
}
return total;
}
ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
{
char *p = buf;
ssize_t total = 0;
while (count > 0) {
ssize_t loaded = xpread(fd, p, count, offset);
if (loaded < 0)
return -1;
if (loaded == 0)
return total;
count -= loaded;
p += loaded;
total += loaded;
offset += loaded;
}
return total;
}
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
int xdup(int fd)
{
int ret = dup(fd);
if (ret < 0)
die_errno("dup failed");
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
return ret;
}
/**
* xfopen() is the same as fopen(), but it die()s if the fopen() fails.
*/
FILE *xfopen(const char *path, const char *mode)
{
for (;;) {
FILE *fp = fopen(path, mode);
if (fp)
return fp;
if (errno == EINTR)
continue;
if (*mode && mode[1] == '+')
die_errno(_("could not open '%s' for reading and writing"), path);
else if (*mode == 'w' || *mode == 'a')
die_errno(_("could not open '%s' for writing"), path);
else
die_errno(_("could not open '%s' for reading"), path);
}
}
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
FILE *xfdopen(int fd, const char *mode)
{
FILE *stream = fdopen(fd, mode);
if (stream == NULL)
die_errno("Out of memory? fdopen failed");
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
return stream;
}
FILE *fopen_for_writing(const char *path)
{
FILE *ret = fopen(path, "w");
if (!ret && errno == EPERM) {
if (!unlink(path))
ret = fopen(path, "w");
else
errno = EPERM;
}
return ret;
}
static void warn_on_inaccessible(const char *path)
{
warning_errno(_("unable to access '%s'"), path);
}
int warn_on_fopen_errors(const char *path)
{
if (errno != ENOENT && errno != ENOTDIR) {
warn_on_inaccessible(path);
return -1;
}
return 0;
}
FILE *fopen_or_warn(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if (fp)
return fp;
warn_on_fopen_errors(path);
return NULL;
}
int xmkstemp(char *filename_template)
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
{
int fd;
char origtemplate[PATH_MAX];
strlcpy(origtemplate, filename_template, sizeof(origtemplate));
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
fd = mkstemp(filename_template);
if (fd < 0) {
int saved_errno = errno;
const char *nonrelative_template;
if (strlen(filename_template) != strlen(origtemplate))
filename_template = origtemplate;
nonrelative_template = absolute_path(filename_template);
errno = saved_errno;
die_errno("Unable to create temporary file '%s'",
nonrelative_template);
}
Shrink the git binary a bit by avoiding unnecessary inline functions So I was looking at the disgusting size of the git binary, and even with the debugging removed, and using -Os instead of -O2, the size of the text section was pretty high. In this day and age I guess almost a megabyte of text isn't really all that surprising, but it still doesn't exactly make me think "lean and mean". With -Os, a surprising amount of text space is wasted on inline functions that end up just being replicated multiple times, and where performance really isn't a valid reason to inline them. In particular, the trivial wrapper functions like "xmalloc()" are used _everywhere_, and making them inline just duplicates the text (and the string we use to 'die()' on failure) unnecessarily. So this just moves them into a "wrapper.c" file, getting rid of a tiny bit of unnecessary bloat. The following numbers are both with "CFLAGS=-Os": Before: [torvalds@woody git]$ size git text data bss dec hex filename 700460 15160 292184 1007804 f60bc git After: [torvalds@woody git]$ size git text data bss dec hex filename 670540 15160 292184 977884 eebdc git so it saves almost 30k of text-space (it actually saves more than that with the default -O2, but I don't think that's necessarily a very relevant number from a "try to shrink git" standpoint). It might conceivably have a performance impact, but none of this should be _that_ performance critical. The real cost is not generally in the wrapper anyway, but in the code it wraps (ie the cost of "xread()" is all in the read itself, not in the trivial wrapping of it). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-06-23 03:19:25 +08:00
return fd;
}
/* Adapted from libiberty's mkstemp.c. */
#undef TMP_MAX
#define TMP_MAX 16384
int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
{
static const char letters[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
static const int num_letters = 62;
uint64_t value;
struct timeval tv;
char *filename_template;
size_t len;
int fd, count;
len = strlen(pattern);
if (len < 6 + suffix_len) {
errno = EINVAL;
return -1;
}
if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
errno = EINVAL;
return -1;
}
/*
* Replace pattern's XXXXXX characters with randomness.
* Try TMP_MAX different filenames.
*/
gettimeofday(&tv, NULL);
value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
filename_template = &pattern[len - 6 - suffix_len];
for (count = 0; count < TMP_MAX; ++count) {
uint64_t v = value;
/* Fill in the random bits. */
filename_template[0] = letters[v % num_letters]; v /= num_letters;
filename_template[1] = letters[v % num_letters]; v /= num_letters;
filename_template[2] = letters[v % num_letters]; v /= num_letters;
filename_template[3] = letters[v % num_letters]; v /= num_letters;
filename_template[4] = letters[v % num_letters]; v /= num_letters;
filename_template[5] = letters[v % num_letters]; v /= num_letters;
fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
if (fd >= 0)
return fd;
/*
* Fatal error (EPERM, ENOSPC etc).
* It doesn't make sense to loop.
*/
if (errno != EEXIST)
break;
/*
* This is a random value. It is only necessary that
* the next TMP_MAX values generated by adding 7777 to
* VALUE are different with (module 2^32).
*/
value += 7777;
}
/* We return the null string if we can't find a unique file name. */
pattern[0] = '\0';
return -1;
}
int git_mkstemp_mode(char *pattern, int mode)
{
/* mkstemp is just mkstemps with no suffix */
return git_mkstemps_mode(pattern, 0, mode);
}
int xmkstemp_mode(char *filename_template, int mode)
{
int fd;
char origtemplate[PATH_MAX];
strlcpy(origtemplate, filename_template, sizeof(origtemplate));
fd = git_mkstemp_mode(filename_template, mode);
if (fd < 0) {
int saved_errno = errno;
const char *nonrelative_template;
if (!filename_template[0])
filename_template = origtemplate;
nonrelative_template = absolute_path(filename_template);
errno = saved_errno;
die_errno("Unable to create temporary file '%s'",
nonrelative_template);
}
return fd;
}
static int warn_if_unremovable(const char *op, const char *file, int rc)
{
int err;
if (!rc || errno == ENOENT)
return 0;
err = errno;
warning_errno("unable to %s '%s'", op, file);
errno = err;
return rc;
}
int unlink_or_msg(const char *file, struct strbuf *err)
{
int rc = unlink(file);
assert(err);
if (!rc || errno == ENOENT)
return 0;
strbuf_addf(err, "unable to unlink '%s': %s",
file, strerror(errno));
return -1;
}
int unlink_or_warn(const char *file)
{
return warn_if_unremovable("unlink", file, unlink(file));
}
int rmdir_or_warn(const char *file)
{
return warn_if_unremovable("rmdir", file, rmdir(file));
}
int remove_or_warn(unsigned int mode, const char *file)
{
return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
}
config: allow inaccessible configuration under $HOME The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files, 2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config permission problems as errors, 2012-10-13) were intended to prevent important configuration (think "[transfer] fsckobjects") from being ignored when the configuration is unintentionally unreadable (for example with EIO on a flaky filesystem, or with ENOMEM due to a DoS attack). Usually ~/.gitconfig and ~/.config/git are readable by the current user, and if they aren't then it would be easy to fix those permissions, so the damage from adding this check should have been minimal. Unfortunately the access() check often trips when git is being run as a server. A daemon (such as inetd or git-daemon) starts as "root", creates a listening socket, and then drops privileges, meaning that when git commands are invoked they cannot access $HOME and die with fatal: unable to access '/root/.config/git/config': Permission denied Any patch to fix this would have one of three problems: 1. We annoy sysadmins who need to take an extra step to handle HOME when dropping privileges (the current behavior, or any other proposal that they have to opt into). 2. We annoy sysadmins who want to set HOME when dropping privileges, either by making what they want to do impossible, or making them set an extra variable or option to accomplish what used to work (e.g., a patch to git-daemon to set HOME when --user is passed). 3. We loosen the check, so some cases which might be noteworthy are not caught. This patch is of type (3). Treat user and xdg configuration that are inaccessible due to permissions (EACCES) as though no user configuration was provided at all. An alternative method would be to check if $HOME is readable, but that would not help in cases where the user who dropped privileges had a globally readable HOME with only .config or .gitconfig being private. This does not change the behavior when /etc/gitconfig or .git/config is unreadable (since those are more serious configuration errors), nor when ~/.gitconfig or ~/.config/git is unreadable due to problems other than permissions. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Improved-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 05:03:18 +08:00
static int access_error_is_ok(int err, unsigned flag)
{
return (is_missing_file_error(err) ||
((flag & ACCESS_EACCES_OK) && err == EACCES));
config: allow inaccessible configuration under $HOME The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files, 2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config permission problems as errors, 2012-10-13) were intended to prevent important configuration (think "[transfer] fsckobjects") from being ignored when the configuration is unintentionally unreadable (for example with EIO on a flaky filesystem, or with ENOMEM due to a DoS attack). Usually ~/.gitconfig and ~/.config/git are readable by the current user, and if they aren't then it would be easy to fix those permissions, so the damage from adding this check should have been minimal. Unfortunately the access() check often trips when git is being run as a server. A daemon (such as inetd or git-daemon) starts as "root", creates a listening socket, and then drops privileges, meaning that when git commands are invoked they cannot access $HOME and die with fatal: unable to access '/root/.config/git/config': Permission denied Any patch to fix this would have one of three problems: 1. We annoy sysadmins who need to take an extra step to handle HOME when dropping privileges (the current behavior, or any other proposal that they have to opt into). 2. We annoy sysadmins who want to set HOME when dropping privileges, either by making what they want to do impossible, or making them set an extra variable or option to accomplish what used to work (e.g., a patch to git-daemon to set HOME when --user is passed). 3. We loosen the check, so some cases which might be noteworthy are not caught. This patch is of type (3). Treat user and xdg configuration that are inaccessible due to permissions (EACCES) as though no user configuration was provided at all. An alternative method would be to check if $HOME is readable, but that would not help in cases where the user who dropped privileges had a globally readable HOME with only .config or .gitconfig being private. This does not change the behavior when /etc/gitconfig or .git/config is unreadable (since those are more serious configuration errors), nor when ~/.gitconfig or ~/.config/git is unreadable due to problems other than permissions. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Improved-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 05:03:18 +08:00
}
int access_or_warn(const char *path, int mode, unsigned flag)
{
int ret = access(path, mode);
config: allow inaccessible configuration under $HOME The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files, 2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config permission problems as errors, 2012-10-13) were intended to prevent important configuration (think "[transfer] fsckobjects") from being ignored when the configuration is unintentionally unreadable (for example with EIO on a flaky filesystem, or with ENOMEM due to a DoS attack). Usually ~/.gitconfig and ~/.config/git are readable by the current user, and if they aren't then it would be easy to fix those permissions, so the damage from adding this check should have been minimal. Unfortunately the access() check often trips when git is being run as a server. A daemon (such as inetd or git-daemon) starts as "root", creates a listening socket, and then drops privileges, meaning that when git commands are invoked they cannot access $HOME and die with fatal: unable to access '/root/.config/git/config': Permission denied Any patch to fix this would have one of three problems: 1. We annoy sysadmins who need to take an extra step to handle HOME when dropping privileges (the current behavior, or any other proposal that they have to opt into). 2. We annoy sysadmins who want to set HOME when dropping privileges, either by making what they want to do impossible, or making them set an extra variable or option to accomplish what used to work (e.g., a patch to git-daemon to set HOME when --user is passed). 3. We loosen the check, so some cases which might be noteworthy are not caught. This patch is of type (3). Treat user and xdg configuration that are inaccessible due to permissions (EACCES) as though no user configuration was provided at all. An alternative method would be to check if $HOME is readable, but that would not help in cases where the user who dropped privileges had a globally readable HOME with only .config or .gitconfig being private. This does not change the behavior when /etc/gitconfig or .git/config is unreadable (since those are more serious configuration errors), nor when ~/.gitconfig or ~/.config/git is unreadable due to problems other than permissions. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Improved-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 05:03:18 +08:00
if (ret && !access_error_is_ok(errno, flag))
warn_on_inaccessible(path);
return ret;
}
config: allow inaccessible configuration under $HOME The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files, 2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config permission problems as errors, 2012-10-13) were intended to prevent important configuration (think "[transfer] fsckobjects") from being ignored when the configuration is unintentionally unreadable (for example with EIO on a flaky filesystem, or with ENOMEM due to a DoS attack). Usually ~/.gitconfig and ~/.config/git are readable by the current user, and if they aren't then it would be easy to fix those permissions, so the damage from adding this check should have been minimal. Unfortunately the access() check often trips when git is being run as a server. A daemon (such as inetd or git-daemon) starts as "root", creates a listening socket, and then drops privileges, meaning that when git commands are invoked they cannot access $HOME and die with fatal: unable to access '/root/.config/git/config': Permission denied Any patch to fix this would have one of three problems: 1. We annoy sysadmins who need to take an extra step to handle HOME when dropping privileges (the current behavior, or any other proposal that they have to opt into). 2. We annoy sysadmins who want to set HOME when dropping privileges, either by making what they want to do impossible, or making them set an extra variable or option to accomplish what used to work (e.g., a patch to git-daemon to set HOME when --user is passed). 3. We loosen the check, so some cases which might be noteworthy are not caught. This patch is of type (3). Treat user and xdg configuration that are inaccessible due to permissions (EACCES) as though no user configuration was provided at all. An alternative method would be to check if $HOME is readable, but that would not help in cases where the user who dropped privileges had a globally readable HOME with only .config or .gitconfig being private. This does not change the behavior when /etc/gitconfig or .git/config is unreadable (since those are more serious configuration errors), nor when ~/.gitconfig or ~/.config/git is unreadable due to problems other than permissions. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Improved-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 05:03:18 +08:00
int access_or_die(const char *path, int mode, unsigned flag)
{
int ret = access(path, mode);
config: allow inaccessible configuration under $HOME The changes v1.7.12.1~2^2~4 (config: warn on inaccessible files, 2012-08-21) and v1.8.1.1~22^2~2 (config: treat user and xdg config permission problems as errors, 2012-10-13) were intended to prevent important configuration (think "[transfer] fsckobjects") from being ignored when the configuration is unintentionally unreadable (for example with EIO on a flaky filesystem, or with ENOMEM due to a DoS attack). Usually ~/.gitconfig and ~/.config/git are readable by the current user, and if they aren't then it would be easy to fix those permissions, so the damage from adding this check should have been minimal. Unfortunately the access() check often trips when git is being run as a server. A daemon (such as inetd or git-daemon) starts as "root", creates a listening socket, and then drops privileges, meaning that when git commands are invoked they cannot access $HOME and die with fatal: unable to access '/root/.config/git/config': Permission denied Any patch to fix this would have one of three problems: 1. We annoy sysadmins who need to take an extra step to handle HOME when dropping privileges (the current behavior, or any other proposal that they have to opt into). 2. We annoy sysadmins who want to set HOME when dropping privileges, either by making what they want to do impossible, or making them set an extra variable or option to accomplish what used to work (e.g., a patch to git-daemon to set HOME when --user is passed). 3. We loosen the check, so some cases which might be noteworthy are not caught. This patch is of type (3). Treat user and xdg configuration that are inaccessible due to permissions (EACCES) as though no user configuration was provided at all. An alternative method would be to check if $HOME is readable, but that would not help in cases where the user who dropped privileges had a globally readable HOME with only .config or .gitconfig being private. This does not change the behavior when /etc/gitconfig or .git/config is unreadable (since those are more serious configuration errors), nor when ~/.gitconfig or ~/.config/git is unreadable due to problems other than permissions. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Improved-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-04-13 05:03:18 +08:00
if (ret && !access_error_is_ok(errno, flag))
die_errno(_("unable to access '%s'"), path);
return ret;
}
char *xgetcwd(void)
{
struct strbuf sb = STRBUF_INIT;
if (strbuf_getcwd(&sb))
die_errno(_("unable to get current working directory"));
return strbuf_detach(&sb, NULL);
}
int xsnprintf(char *dst, size_t max, const char *fmt, ...)
{
va_list ap;
int len;
va_start(ap, fmt);
len = vsnprintf(dst, max, fmt, ap);
va_end(ap);
if (len < 0)
BUG("your snprintf is broken");
if (len >= max)
BUG("attempt to snprintf into too-small buffer");
return len;
}
void write_file_buf(const char *path, const char *buf, size_t len)
{
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
avoid "write_in_full(fd, buf, len) != len" pattern The return value of write_in_full() is either "-1", or the requested number of bytes[1]. If we make a partial write before seeing an error, we still return -1, not a partial value. This goes back to f6aa66cb95 (write_in_full: really write in full or return error on disk full., 2007-01-11). So checking anything except "was the return value negative" is pointless. And there are a couple of reasons not to do so: 1. It can do a funny signed/unsigned comparison. If your "len" is signed (e.g., a size_t) then the compiler will promote the "-1" to its unsigned variant. This works out for "!= len" (unless you really were trying to write the maximum size_t bytes), but is a bug if you check "< len" (an example of which was fixed recently in config.c). We should avoid promoting the mental model that you need to check the length at all, so that new sites are not tempted to copy us. 2. Checking for a negative value is shorter to type, especially when the length is an expression. 3. Linus says so. In d34cf19b89 (Clean up write_in_full() users, 2007-01-11), right after the write_in_full() semantics were changed, he wrote: I really wish every "write_in_full()" user would just check against "<0" now, but this fixes the nasty and stupid ones. Appeals to authority aside, this makes it clear that writing it this way does not have an intentional benefit. It's a historical curiosity that we never bothered to clean up (and which was undoubtedly cargo-culted into new sites). So let's convert these obviously-correct cases (this includes write_str_in_full(), which is just a wrapper for write_in_full()). [1] A careful reader may notice there is one way that write_in_full() can return a different value. If we ask write() to write N bytes and get a return value that is _larger_ than N, we could return a larger total. But besides the fact that this would imply a totally broken version of write(), it would already invoke undefined behavior. Our internal remaining counter is an unsigned size_t, which means that subtracting too many byte will wrap it around to a very large number. So we'll instantly begin reading off the end of the buffer, trying to write gigabytes (or petabytes) of data. Signed-off-by: Jeff King <peff@peff.net> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-14 01:16:03 +08:00
if (write_in_full(fd, buf, len) < 0)
die_errno(_("could not write to '%s'"), path);
if (close(fd))
die_errno(_("could not close '%s'"), path);
}
void write_file(const char *path, const char *fmt, ...)
{
va_list params;
struct strbuf sb = STRBUF_INIT;
va_start(params, fmt);
strbuf_vaddf(&sb, fmt, params);
va_end(params);
strbuf_complete_line(&sb);
write_file_buf(path, sb.buf, sb.len);
strbuf_release(&sb);
}
void sleep_millisec(int millisec)
{
poll(NULL, 0, millisec);
}
int xgethostname(char *buf, size_t len)
{
/*
* If the full hostname doesn't fit in buf, POSIX does not
* specify whether the buffer will be null-terminated, so to
* be safe, do it ourselves.
*/
int ret = gethostname(buf, len);
if (!ret)
buf[len - 1] = 0;
return ret;
}