From f4626df51f63d53b89ff01de54cbf7558217ea2b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 1 Dec 2007 21:24:59 +0100 Subject: Add target architecture MinGW. With this change GIT can be compiled and linked using MinGW. Builtins that only read the repository such as the log family and grep already work. Simple stubs are provided for a number of functions that the Windows C runtime does not offer. They will be completed in later patches. However, a fix for the snprintf/vsnprintf replacement is applied here to avoid buffer overflows. Dmitry Kakurin pointed out that access(..., X_OK) would always fails on Vista and suggested the -D__USE_MINGW_ACCESS workaround. Signed-off-by: Johannes Sixt --- git-compat-util.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index c04e8baa87..da7249ac1c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -63,17 +63,18 @@ #include #include #include -#include #include +#include +#include +#include +#ifndef __MINGW32__ +#include #include #include #include -#include #ifndef NO_SYS_SELECT_H #include #endif -#include -#include #include #include #include @@ -89,6 +90,10 @@ #include #define _ALL_SOURCE 1 #endif +#else /* __MINGW32__ */ +/* pull in Windows compatibility stuff */ +#include "compat/mingw.h" +#endif /* __MINGW32__ */ #ifndef NO_ICONV #include -- cgit v1.3 From 80ba074f4163dc8ee4232d64e73a8521edcadc1d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 3 Dec 2007 21:55:57 +0100 Subject: Windows: Use the Windows style PATH separator ';'. Signed-off-by: Johannes Sixt --- Documentation/git.txt | 6 +++--- compat/mingw.h | 6 ++++++ exec_cmd.c | 2 +- git-compat-util.h | 4 ++++ sha1_file.c | 2 +- 5 files changed, 15 insertions(+), 5 deletions(-) (limited to 'git-compat-util.h') diff --git a/Documentation/git.txt b/Documentation/git.txt index 7414238fe5..4e4bd6ddb1 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -409,9 +409,9 @@ git so take care if using Cogito etc. 'GIT_ALTERNATE_OBJECT_DIRECTORIES':: Due to the immutable nature of git objects, old objects can be archived into shared, read-only directories. This variable - specifies a ":" separated list of git object directories which - can be used to search for git objects. New objects will not be - written to these directories. + specifies a ":" separated (on Windows ";" separated) list + of git object directories which can be used to search for git + objects. New objects will not be written to these directories. 'GIT_DIR':: If the 'GIT_DIR' environment variable is set then it diff --git a/compat/mingw.h b/compat/mingw.h index e5c0c6ba21..22aae0077e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -132,3 +132,9 @@ int getpagesize(void); /* defined in MinGW's libgcc.a */ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); + +/* + * git specific compatibility + */ + +#define PATH_SEP ';' diff --git a/exec_cmd.c b/exec_cmd.c index e189caca62..a1bc4e04bf 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -37,7 +37,7 @@ static void add_path(struct strbuf *out, const char *path) else strbuf_addstr(out, make_absolute_path(path)); - strbuf_addch(out, ':'); + strbuf_addch(out, PATH_SEP); } } diff --git a/git-compat-util.h b/git-compat-util.h index da7249ac1c..9dc733e56c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -110,6 +110,10 @@ #define PRIuMAX "llu" #endif +#ifndef PATH_SEP +#define PATH_SEP ':' +#endif + #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else diff --git a/sha1_file.c b/sha1_file.c index 191f814e09..6f004ffd09 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -392,7 +392,7 @@ void prepare_alt_odb(void) if (!alt) alt = ""; alt_odb_tail = &alt_odb_list; - link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0); + link_alt_odb_entries(alt, alt + strlen(alt), PATH_SEP, NULL, 0); read_info_alternates(get_object_directory(), 0); } -- cgit v1.3 From 25fe217b86ca40c53e710d776e120dfa0d81f60b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Mar 2008 21:51:27 +0100 Subject: Windows: Treat Windows style path names. GIT's guts work with a forward slash as a path separators. We do not change that. Rather we make sure that only "normalized" paths enter the depths of the machinery. We have to translate backslashes to forward slashes in the prefix and in command line arguments. Fortunately, all of them are passed through functions in setup.c. A macro has_dos_drive_path() is defined that checks whether a path begins with a drive letter+colon combination. This predicate is always false on Unix. Another macro is_dir_sep() abstracts that a backslash is also a directory separator on Windows. Signed-off-by: Johannes Sixt --- cache.h | 2 +- compat/mingw.c | 13 +++++++++++++ compat/mingw.h | 9 +++++++++ git-compat-util.h | 8 ++++++++ setup.c | 50 ++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 67 insertions(+), 15 deletions(-) (limited to 'git-compat-util.h') diff --git a/cache.h b/cache.h index 81b7e17de2..72544de4ce 100644 --- a/cache.h +++ b/cache.h @@ -521,7 +521,7 @@ int safe_create_leading_directories(char *path); char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) { - return path[0] == '/'; + return path[0] == '/' || has_dos_drive_prefix(path); } const char *make_absolute_path(const char *path); const char *make_nonrelative_path(const char *path); diff --git a/compat/mingw.c b/compat/mingw.c index 075448d245..4e559bdc93 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -40,6 +40,19 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) return result; } +#undef getcwd +char *mingw_getcwd(char *pointer, int len) +{ + int i; + char *ret = getcwd(pointer, len); + if (!ret) + return ret; + for (i = 0; pointer[i]; i++) + if (pointer[i] == '\\') + pointer[i] = '/'; + return ret; +} + struct passwd *getpwuid(int uid) { static struct passwd p; diff --git a/compat/mingw.h b/compat/mingw.h index 22aae0077e..a954014ff2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -133,8 +133,17 @@ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); +/* + * replacements of existing functions + */ + +char *mingw_getcwd(char *pointer, int len); +#define getcwd mingw_getcwd + /* * git specific compatibility */ +#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') +#define is_dir_sep(c) ((c) == '/' || (c) == '\\') #define PATH_SEP ';' diff --git a/git-compat-util.h b/git-compat-util.h index 9dc733e56c..ab762c79ee 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -114,6 +114,14 @@ #define PATH_SEP ':' #endif +#ifndef has_dos_drive_prefix +#define has_dos_drive_prefix(path) 0 +#endif + +#ifndef is_dir_sep +#define is_dir_sep(c) ((c) == '/') +#endif + #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else diff --git a/setup.c b/setup.c index 5fc89fd7da..8bb7b10174 100644 --- a/setup.c +++ b/setup.c @@ -6,11 +6,17 @@ static int inside_work_tree = -1; static int sanitary_path_copy(char *dst, const char *src) { - char *dst0 = dst; + char *dst0; - if (*src == '/') { + if (has_dos_drive_prefix(src)) { + *dst++ = *src++; + *dst++ = *src++; + } + dst0 = dst; + + if (is_dir_sep(*src)) { *dst++ = '/'; - while (*src == '/') + while (is_dir_sep(*src)) src++; } @@ -29,10 +35,10 @@ static int sanitary_path_copy(char *dst, const char *src) if (!src[1]) { /* (1) */ src++; - } else if (src[1] == '/') { + } else if (is_dir_sep(src[1])) { /* (2) */ src += 2; - while (*src == '/') + while (is_dir_sep(*src)) src++; continue; } else if (src[1] == '.') { @@ -40,10 +46,10 @@ static int sanitary_path_copy(char *dst, const char *src) /* (3) */ src += 2; goto up_one; - } else if (src[2] == '/') { + } else if (is_dir_sep(src[2])) { /* (4) */ src += 3; - while (*src == '/') + while (is_dir_sep(*src)) src++; goto up_one; } @@ -51,11 +57,11 @@ static int sanitary_path_copy(char *dst, const char *src) } /* copy up to the next '/', and eat all '/' */ - while ((c = *src++) != '\0' && c != '/') + while ((c = *src++) != '\0' && !is_dir_sep(c)) *dst++ = c; - if (c == '/') { - *dst++ = c; - while (c == '/') + if (is_dir_sep(c)) { + *dst++ = '/'; + while (is_dir_sep(c)) c = *src++; src--; } else if (!c) @@ -74,7 +80,7 @@ static int sanitary_path_copy(char *dst, const char *src) if (dst <= dst0) break; c = *dst--; - if (c == '/') { + if (c == '/') { /* MinGW: cannot be '\\' anymore */ dst += 2; break; } @@ -123,10 +129,23 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; +#ifndef __MINGW32__ if (!pfx || !*pfx || is_absolute_path(arg)) return arg; memcpy(path, pfx, pfx_len); strcpy(path + pfx_len, arg); +#else + char *p; + /* don't add prefix to absolute paths, but still replace '\' by '/' */ + if (is_absolute_path(arg)) + pfx_len = 0; + else + memcpy(path, pfx, pfx_len); + strcpy(path + pfx_len, arg); + for (p = path + pfx_len; *p; p++) + if (*p == '\\') + *p = '/'; +#endif return path; } @@ -360,6 +379,7 @@ const char *setup_git_directory_gently(int *nongit_ok) const char *gitdirenv; const char *gitfile_dir; int len, offset; + int minoffset = 0; /* * Let's assume that we are in a git repository. @@ -410,6 +430,8 @@ const char *setup_git_directory_gently(int *nongit_ok) if (!getcwd(cwd, sizeof(cwd)-1)) die("Unable to read current working directory"); + if (has_dos_drive_prefix(cwd)) + minoffset = 2; /* * Test in the following order (relative to the cwd): @@ -442,7 +464,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } chdir(".."); do { - if (!offset) { + if (offset <= minoffset) { if (nongit_ok) { if (chdir(cwd)) die("Cannot come back to cwd"); @@ -451,7 +473,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } die("Not a git repository"); } - } while (cwd[--offset] != '/'); + } while (offset > minoffset && cwd[--offset] != '/'); } inside_git_dir = 0; -- cgit v1.3 From 23326d14edbd16469453f6c3ecdd98ab90e6efb7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 20:57:25 +0100 Subject: Windows: Strip ".exe" from the program name. Before we can successfully parse a builtin command from the program name we must strip off unneeded parts, that is, the file extension. Furthermore, we must take Windows style path names into account when we parse the program name. Signed-off-by: Johannes Sixt --- Makefile | 1 + git-compat-util.h | 4 ++++ git.c | 19 ++++++++++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) (limited to 'git-compat-util.h') diff --git a/Makefile b/Makefile index a7dafa7586..9c5aae03bb 100644 --- a/Makefile +++ b/Makefile @@ -735,6 +735,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_POSIX_ONLY_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 + COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe diff --git a/git-compat-util.h b/git-compat-util.h index ab762c79ee..a9a85be89d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -114,6 +114,10 @@ #define PATH_SEP ':' #endif +#ifndef STRIP_EXTENSION +#define STRIP_EXTENSION "" +#endif + #ifndef has_dos_drive_prefix #define has_dos_drive_prefix(path) 0 #endif diff --git a/git.c b/git.c index 59f0fcc1f2..871b93ca7e 100644 --- a/git.c +++ b/git.c @@ -369,6 +369,16 @@ static void handle_internal_command(int argc, const char **argv) { "pack-refs", cmd_pack_refs, RUN_SETUP }, }; int i; + static const char ext[] = STRIP_EXTENSION; + + if (sizeof(ext) > 1) { + i = strlen(argv[0]) - strlen(ext); + if (i > 0 && !strcmp(argv[0] + i, ext)) { + char *argv0 = strdup(argv[0]); + argv[0] = cmd = argv0; + argv0[i] = '\0'; + } + } /* Turn "git cmd --help" into "git help cmd" */ if (argc > 1 && !strcmp(argv[1], "--help")) { @@ -386,8 +396,8 @@ static void handle_internal_command(int argc, const char **argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] ? argv[0] : "git-help"; - char *slash = strrchr(cmd, '/'); + const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; + char *slash = (char *)cmd + strlen(cmd); const char *cmd_path = NULL; int done_alias = 0; @@ -396,7 +406,10 @@ int main(int argc, const char **argv) * name, and the dirname as the default exec_path * if we don't have anything better. */ - if (slash) { + do + --slash; + while (cmd <= slash && !is_dir_sep(*slash)); + if (cmd <= slash) { *slash++ = 0; cmd_path = cmd; cmd = slash; -- cgit v1.3 From bb5799d6ef3ad7ee70a138b82e67b93e3aaa8017 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 08:31:41 +0200 Subject: Make my_mktime() public and rename it to tm_to_time_t() We will use it from the MinGW port's gettimeofday() substitution. Signed-off-by: Johannes Sixt --- date.c | 13 ++++++++----- git-compat-util.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'git-compat-util.h') diff --git a/date.c b/date.c index 1a4eb87b01..35a52576c5 100644 --- a/date.c +++ b/date.c @@ -6,7 +6,10 @@ #include "cache.h" -static time_t my_mktime(struct tm *tm) +/* + * This is like mktime, but without normalization of tm_wday and tm_yday. + */ +time_t tm_to_time_t(const struct tm *tm) { static const int mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 @@ -67,7 +70,7 @@ static int local_tzoffset(unsigned long time) t = time; localtime_r(&t, &tm); - t_local = my_mktime(&tm); + t_local = tm_to_time_t(&tm); if (t_local < t) { eastwest = -1; @@ -322,7 +325,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, if (!now_tm) return 1; - specified = my_mktime(r); + specified = tm_to_time_t(r); /* Be it commit time or author time, it does not make * sense to specify timestamp way into the future. Make @@ -572,7 +575,7 @@ int parse_date(const char *date, char *result, int maxlen) } /* mktime uses local timezone */ - then = my_mktime(&tm); + then = tm_to_time_t(&tm); if (offset == -1) offset = (then - mktime(&tm)) / 60; @@ -611,7 +614,7 @@ void datestamp(char *buf, int bufsize) time(&now); - offset = my_mktime(localtime(&now)) - now; + offset = tm_to_time_t(localtime(&now)) - now; offset /= 60; date_string(now, offset, buf, bufsize); diff --git a/git-compat-util.h b/git-compat-util.h index a9a85be89d..58cdc087fa 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -147,6 +147,7 @@ extern void set_error_routine(void (*routine)(const char *err, va_list params)); extern void set_warn_routine(void (*routine)(const char *warn, va_list params)); extern int prefixcmp(const char *str, const char *prefix); +extern time_t tm_to_time_t(const struct tm *tm); #ifdef NO_MMAP -- cgit v1.3 From 14086b0a13f5f5ac456cb9ae16a263f92908ae61 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:48:14 +0100 Subject: compat/pread.c: Add a forward declaration to fix a warning read_in_full()'s is used in compat/pread.c. read_in_full() is declared in cache.h. But we can't include cache.h because too many macros are defined there. Using read_in_full() without including cache.h is dangerous because we wouldn't recognize if its prototyp changed. gcc issues a warning about that. This commit adds a forward declaration to git-compat-util.h. git-compat-util.h is included by compat/pread.c _and_ cache.h. Hence, changes in cache.h would be detected. Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- git-compat-util.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index 58cdc087fa..51823ae7af 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -185,6 +185,12 @@ extern int git_munmap(void *start, size_t length); #define pread git_pread extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif +/* + * Forward decl that will remind us if its twin in cache.h changes. + * This function is used in compat/pread.c. But we can't include + * cache.h there. + */ +extern ssize_t read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv -- cgit v1.3