diff options
Diffstat (limited to 'compat')
-rw-r--r-- | compat/cygwin.c | 7 | ||||
-rw-r--r-- | compat/fnmatch/fnmatch.c | 2 | ||||
-rw-r--r-- | compat/mingw.c | 88 | ||||
-rw-r--r-- | compat/mingw.h | 8 | ||||
-rw-r--r-- | compat/mkdir.c | 24 | ||||
-rw-r--r-- | compat/poll/poll.c (renamed from compat/win32/poll.c) | 14 | ||||
-rw-r--r-- | compat/poll/poll.h (renamed from compat/win32/poll.h) | 0 | ||||
-rw-r--r-- | compat/precompose_utf8.c | 184 | ||||
-rw-r--r-- | compat/precompose_utf8.h | 45 | ||||
-rw-r--r-- | compat/terminal.c | 129 |
10 files changed, 441 insertions, 60 deletions
diff --git a/compat/cygwin.c b/compat/cygwin.c index dfe9b3084f..5428858875 100644 --- a/compat/cygwin.c +++ b/compat/cygwin.c @@ -1,6 +1,13 @@ #define WIN32_LEAN_AND_MEAN +#ifdef CYGWIN_V15_WIN32API #include "../git-compat-util.h" #include "win32.h" +#else +#include <sys/stat.h> +#include <sys/errno.h> +#include "win32.h" +#include "../git-compat-util.h" +#endif #include "../cache.h" /* to read configuration */ static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts) diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 9473aed2bb..0ff1d273a5 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -345,7 +345,7 @@ internal_fnmatch (pattern, string, no_leading_period, flags) for (;;) { - if (c1 == CHAR_CLASS_MAX_LENGTH) + if (c1 > CHAR_CLASS_MAX_LENGTH) /* The name is too long and therefore the pattern is ill-formed. */ return FNM_NOMATCH; diff --git a/compat/mingw.c b/compat/mingw.c index 28527abe22..b673625580 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -321,6 +321,31 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) return write(fd, buf, min(count, 31 * 1024 * 1024)); } +static BOOL WINAPI ctrl_ignore(DWORD type) +{ + return TRUE; +} + +#undef fgetc +int mingw_fgetc(FILE *stream) +{ + int ch; + if (!isatty(_fileno(stream))) + return fgetc(stream); + + SetConsoleCtrlHandler(ctrl_ignore, TRUE); + while (1) { + ch = fgetc(stream); + if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED) + break; + + /* Ctrl+C was pressed, simulate SIGINT and retry */ + mingw_raise(SIGINT); + } + SetConsoleCtrlHandler(ctrl_ignore, FALSE); + return ch; +} + #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { @@ -1548,7 +1573,7 @@ static HANDLE timer_event; static HANDLE timer_thread; static int timer_interval; static int one_shot; -static sig_handler_t timer_fn = SIG_DFL; +static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL; /* The timer works like this: * The thread, ticktack(), is a trivial routine that most of the time @@ -1562,10 +1587,7 @@ static sig_handler_t timer_fn = SIG_DFL; static unsigned __stdcall ticktack(void *dummy) { while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { - if (timer_fn == SIG_DFL) - die("Alarm"); - if (timer_fn != SIG_IGN) - timer_fn(SIGALRM); + mingw_raise(SIGALRM); if (one_shot) break; } @@ -1656,12 +1678,49 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out) sig_handler_t mingw_signal(int sig, sig_handler_t handler) { sig_handler_t old = timer_fn; - if (sig != SIGALRM) + + switch (sig) { + case SIGALRM: + timer_fn = handler; + break; + + case SIGINT: + sigint_fn = handler; + break; + + default: return signal(sig, handler); - timer_fn = handler; + } + return old; } +#undef raise +int mingw_raise(int sig) +{ + switch (sig) { + case SIGALRM: + if (timer_fn == SIG_DFL) { + if (isatty(STDERR_FILENO)) + fputs("Alarm clock\n", stderr); + exit(128 + SIGALRM); + } else if (timer_fn != SIG_IGN) + timer_fn(SIGALRM); + return 0; + + case SIGINT: + if (sigint_fn == SIG_DFL) + exit(128 + SIGINT); + else if (sigint_fn != SIG_IGN) + sigint_fn(SIGINT); + return 0; + + default: + return raise(sig); + } +} + + static const char *make_backslash_path(const char *path) { static char buf[PATH_MAX + 1]; @@ -1723,21 +1782,6 @@ int link(const char *oldpath, const char *newpath) return 0; } -char *getpass(const char *prompt) -{ - struct strbuf buf = STRBUF_INIT; - - fputs(prompt, stderr); - for (;;) { - char c = _getch(); - if (c == '\r' || c == '\n') - break; - strbuf_addch(&buf, c); - } - fputs("\n", stderr); - return strbuf_detach(&buf, NULL); -} - pid_t waitpid(pid_t pid, int *status, int options) { HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, diff --git a/compat/mingw.h b/compat/mingw.h index eeb08d120b..685cd2c3d4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -55,8 +55,6 @@ struct passwd { char *pw_dir; }; -extern char *getpass(const char *prompt); - typedef void (__cdecl *sig_handler_t)(int); struct sigaction { sig_handler_t sa_handler; @@ -179,6 +177,9 @@ int mingw_open (const char *filename, int oflags, ...); ssize_t mingw_write(int fd, const void *buf, size_t count); #define write mingw_write +int mingw_fgetc(FILE *stream); +#define fgetc mingw_fgetc + FILE *mingw_fopen (const char *filename, const char *otype); #define fopen mingw_fopen @@ -290,6 +291,9 @@ static inline unsigned int git_ntohl(unsigned int x) sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +int mingw_raise(int sig); +#define raise mingw_raise + /* * ANSI emulation wrappers */ diff --git a/compat/mkdir.c b/compat/mkdir.c new file mode 100644 index 0000000000..9e253fb72f --- /dev/null +++ b/compat/mkdir.c @@ -0,0 +1,24 @@ +#include "../git-compat-util.h" +#undef mkdir + +/* for platforms that can't deal with a trailing '/' */ +int compat_mkdir_wo_trailing_slash(const char *dir, mode_t mode) +{ + int retval; + char *tmp_dir = NULL; + size_t len = strlen(dir); + + if (len && dir[len-1] == '/') { + if ((tmp_dir = strdup(dir)) == NULL) + return -1; + tmp_dir[len-1] = '\0'; + } + else + tmp_dir = (char *)dir; + + retval = mkdir(tmp_dir, mode); + if (tmp_dir != dir) + free(tmp_dir); + + return retval; +} diff --git a/compat/win32/poll.c b/compat/poll/poll.c index 403eaa7a3c..7d226ecb29 100644 --- a/compat/win32/poll.c +++ b/compat/poll/poll.c @@ -24,7 +24,9 @@ # pragma GCC diagnostic ignored "-Wtype-limits" #endif -#include <malloc.h> +#if defined(WIN32) +# include <malloc.h> +#endif #include <sys/types.h> @@ -48,7 +50,9 @@ #else # include <sys/time.h> # include <sys/socket.h> -# include <sys/select.h> +# ifndef NO_SYS_SELECT_H +# include <sys/select.h> +# endif # include <unistd.h> #endif @@ -302,6 +306,10 @@ compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds) || socket_errno == ECONNABORTED || socket_errno == ENETRESET) happened |= POLLHUP; + /* some systems can't use recv() on non-socket, including HP NonStop */ + else if (/* (r == -1) && */ socket_errno == ENOTSOCK) + happened |= (POLLIN | POLLRDNORM) & sought; + else happened |= POLLERR; } @@ -349,7 +357,7 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout) /* EFAULT is not necessary to implement, but let's do it in the simplest case. */ - if (!pfd) + if (!pfd && nfd) { errno = EFAULT; return -1; diff --git a/compat/win32/poll.h b/compat/poll/poll.h index b7aa59d973..b7aa59d973 100644 --- a/compat/win32/poll.h +++ b/compat/poll/poll.h diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c new file mode 100644 index 0000000000..8cf59558e1 --- /dev/null +++ b/compat/precompose_utf8.c @@ -0,0 +1,184 @@ +/* + * Converts filenames from decomposed unicode into precomposed unicode. + * Used on MacOS X. + */ + +#define PRECOMPOSE_UNICODE_C + +#include "cache.h" +#include "utf8.h" +#include "precompose_utf8.h" + +typedef char *iconv_ibp; +static const char *repo_encoding = "UTF-8"; +static const char *path_encoding = "UTF-8-MAC"; + +static size_t has_non_ascii(const char *s, size_t maxlen, size_t *strlen_c) +{ + const uint8_t *ptr = (const uint8_t *)s; + size_t strlen_chars = 0; + size_t ret = 0; + + if (!ptr || !*ptr) + return 0; + + while (*ptr && maxlen) { + if (*ptr & 0x80) + ret++; + strlen_chars++; + ptr++; + maxlen--; + } + if (strlen_c) + *strlen_c = strlen_chars; + + return ret; +} + + +void probe_utf8_pathname_composition(char *path, int len) +{ + static const char *auml_nfc = "\xc3\xa4"; + static const char *auml_nfd = "\x61\xcc\x88"; + int output_fd; + if (precomposed_unicode != -1) + return; /* We found it defined in the global config, respect it */ + strcpy(path + len, auml_nfc); + output_fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600); + if (output_fd >= 0) { + close(output_fd); + strcpy(path + len, auml_nfd); + /* Indicate to the user, that we can configure it to true */ + if (!access(path, R_OK)) + git_config_set("core.precomposeunicode", "false"); + /* To be backward compatible, set precomposed_unicode to 0 */ + precomposed_unicode = 0; + strcpy(path + len, auml_nfc); + if (unlink(path)) + die_errno(_("failed to unlink '%s'"), path); + } +} + + +void precompose_argv(int argc, const char **argv) +{ + int i = 0; + const char *oldarg; + char *newarg; + iconv_t ic_precompose; + + if (precomposed_unicode != 1) + return; + + ic_precompose = iconv_open(repo_encoding, path_encoding); + if (ic_precompose == (iconv_t) -1) + return; + + while (i < argc) { + size_t namelen; + oldarg = argv[i]; + if (has_non_ascii(oldarg, (size_t)-1, &namelen)) { + newarg = reencode_string_iconv(oldarg, namelen, ic_precompose); + if (newarg) + argv[i] = newarg; + } + i++; + } + iconv_close(ic_precompose); +} + + +PREC_DIR *precompose_utf8_opendir(const char *dirname) +{ + PREC_DIR *prec_dir = xmalloc(sizeof(PREC_DIR)); + prec_dir->dirent_nfc = xmalloc(sizeof(dirent_prec_psx)); + prec_dir->dirent_nfc->max_name_len = sizeof(prec_dir->dirent_nfc->d_name); + + prec_dir->dirp = opendir(dirname); + if (!prec_dir->dirp) { + free(prec_dir->dirent_nfc); + free(prec_dir); + return NULL; + } else { + int ret_errno = errno; + prec_dir->ic_precompose = iconv_open(repo_encoding, path_encoding); + /* if iconv_open() fails, die() in readdir() if needed */ + errno = ret_errno; + } + + return prec_dir; +} + +struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir) +{ + struct dirent *res; + res = readdir(prec_dir->dirp); + if (res) { + size_t namelenz = strlen(res->d_name) + 1; /* \0 */ + size_t new_maxlen = namelenz; + + int ret_errno = errno; + + if (new_maxlen > prec_dir->dirent_nfc->max_name_len) { + size_t new_len = sizeof(dirent_prec_psx) + new_maxlen - + sizeof(prec_dir->dirent_nfc->d_name); + + prec_dir->dirent_nfc = xrealloc(prec_dir->dirent_nfc, new_len); + prec_dir->dirent_nfc->max_name_len = new_maxlen; + } + + prec_dir->dirent_nfc->d_ino = res->d_ino; + prec_dir->dirent_nfc->d_type = res->d_type; + + if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) { + if (prec_dir->ic_precompose == (iconv_t)-1) { + die("iconv_open(%s,%s) failed, but needed:\n" + " precomposed unicode is not supported.\n" + " If you wnat to use decomposed unicode, run\n" + " \"git config core.precomposeunicode false\"\n", + repo_encoding, path_encoding); + } else { + iconv_ibp cp = (iconv_ibp)res->d_name; + size_t inleft = namelenz; + char *outpos = &prec_dir->dirent_nfc->d_name[0]; + size_t outsz = prec_dir->dirent_nfc->max_name_len; + size_t cnt; + errno = 0; + cnt = iconv(prec_dir->ic_precompose, &cp, &inleft, &outpos, &outsz); + if (errno || inleft) { + /* + * iconv() failed and errno could be E2BIG, EILSEQ, EINVAL, EBADF + * MacOS X avoids illegal byte sequemces. + * If they occur on a mounted drive (e.g. NFS) it is not worth to + * die() for that, but rather let the user see the original name + */ + namelenz = 0; /* trigger strlcpy */ + } + } + } else + namelenz = 0; + + if (!namelenz) + strlcpy(prec_dir->dirent_nfc->d_name, res->d_name, + prec_dir->dirent_nfc->max_name_len); + + errno = ret_errno; + return prec_dir->dirent_nfc; + } + return NULL; +} + + +int precompose_utf8_closedir(PREC_DIR *prec_dir) +{ + int ret_value; + int ret_errno; + ret_value = closedir(prec_dir->dirp); + ret_errno = errno; + if (prec_dir->ic_precompose != (iconv_t)-1) + iconv_close(prec_dir->ic_precompose); + free(prec_dir->dirent_nfc); + free(prec_dir); + errno = ret_errno; + return ret_value; +} diff --git a/compat/precompose_utf8.h b/compat/precompose_utf8.h new file mode 100644 index 0000000000..3b73585fc5 --- /dev/null +++ b/compat/precompose_utf8.h @@ -0,0 +1,45 @@ +#ifndef PRECOMPOSE_UNICODE_H +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <iconv.h> + + +typedef struct dirent_prec_psx { + ino_t d_ino; /* Posix */ + size_t max_name_len; /* See below */ + unsigned char d_type; /* available on all systems git runs on */ + + /* + * See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html + * NAME_MAX + 1 should be enough, but some systems have + * NAME_MAX=255 and strlen(d_name) may return 508 or 510 + * Solution: allocate more when needed, see precompose_utf8_readdir() + */ + char d_name[NAME_MAX+1]; +} dirent_prec_psx; + + +typedef struct { + iconv_t ic_precompose; + DIR *dirp; + struct dirent_prec_psx *dirent_nfc; +} PREC_DIR; + +void precompose_argv(int argc, const char **argv); +void probe_utf8_pathname_composition(char *, int); + +PREC_DIR *precompose_utf8_opendir(const char *dirname); +struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *dirp); +int precompose_utf8_closedir(PREC_DIR *dirp); + +#ifndef PRECOMPOSE_UNICODE_C +#define dirent dirent_prec_psx +#define opendir(n) precompose_utf8_opendir(n) +#define readdir(d) precompose_utf8_readdir(d) +#define closedir(d) precompose_utf8_closedir(d) +#define DIR PREC_DIR +#endif /* PRECOMPOSE_UNICODE_C */ + +#define PRECOMPOSE_UNICODE_H +#endif /* PRECOMPOSE_UNICODE_H */ diff --git a/compat/terminal.c b/compat/terminal.c index bbb038dd01..9b5e3d1bb8 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -3,8 +3,22 @@ #include "sigchain.h" #include "strbuf.h" +#if defined(HAVE_DEV_TTY) || defined(WIN32) + +static void restore_term(void); + +static void restore_term_on_signal(int sig) +{ + restore_term(); + sigchain_pop(sig); + raise(sig); +} + #ifdef HAVE_DEV_TTY +#define INPUT_PATH "/dev/tty" +#define OUTPUT_PATH "/dev/tty" + static int term_fd = -1; static struct termios old_term; @@ -14,58 +28,109 @@ static void restore_term(void) return; tcsetattr(term_fd, TCSAFLUSH, &old_term); + close(term_fd); term_fd = -1; } -static void restore_term_on_signal(int sig) +static int disable_echo(void) { - restore_term(); - sigchain_pop(sig); - raise(sig); + struct termios t; + + term_fd = open("/dev/tty", O_RDWR); + if (tcgetattr(term_fd, &t) < 0) + goto error; + + old_term = t; + sigchain_push_common(restore_term_on_signal); + + t.c_lflag &= ~ECHO; + if (!tcsetattr(term_fd, TCSAFLUSH, &t)) + return 0; + +error: + close(term_fd); + term_fd = -1; + return -1; +} + +#elif defined(WIN32) + +#define INPUT_PATH "CONIN$" +#define OUTPUT_PATH "CONOUT$" +#define FORCE_TEXT "t" + +static HANDLE hconin = INVALID_HANDLE_VALUE; +static DWORD cmode; + +static void restore_term(void) +{ + if (hconin == INVALID_HANDLE_VALUE) + return; + + SetConsoleMode(hconin, cmode); + CloseHandle(hconin); + hconin = INVALID_HANDLE_VALUE; } +static int disable_echo(void) +{ + hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hconin == INVALID_HANDLE_VALUE) + return -1; + + GetConsoleMode(hconin, &cmode); + sigchain_push_common(restore_term_on_signal); + if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) { + CloseHandle(hconin); + hconin = INVALID_HANDLE_VALUE; + return -1; + } + + return 0; +} + +#endif + +#ifndef FORCE_TEXT +#define FORCE_TEXT +#endif + char *git_terminal_prompt(const char *prompt, int echo) { static struct strbuf buf = STRBUF_INIT; int r; - FILE *fh; + FILE *input_fh, *output_fh; - fh = fopen("/dev/tty", "w+"); - if (!fh) + input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT); + if (!input_fh) return NULL; - if (!echo) { - struct termios t; - - if (tcgetattr(fileno(fh), &t) < 0) { - fclose(fh); - return NULL; - } - - old_term = t; - term_fd = fileno(fh); - sigchain_push_common(restore_term_on_signal); - - t.c_lflag &= ~ECHO; - if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) { - term_fd = -1; - fclose(fh); - return NULL; - } + output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT); + if (!output_fh) { + fclose(input_fh); + return NULL; + } + + if (!echo && disable_echo()) { + fclose(input_fh); + fclose(output_fh); + return NULL; } - fputs(prompt, fh); - fflush(fh); + fputs(prompt, output_fh); + fflush(output_fh); - r = strbuf_getline(&buf, fh, '\n'); + r = strbuf_getline(&buf, input_fh, '\n'); if (!echo) { - fseek(fh, SEEK_CUR, 0); - putc('\n', fh); - fflush(fh); + putc('\n', output_fh); + fflush(output_fh); } restore_term(); - fclose(fh); + fclose(input_fh); + fclose(output_fh); if (r == EOF) return NULL; |