Accept trailing slashes in lstat() implementation.
[git/mingw.git] / compat / mingw.c
blobac8b8e041498f32024f5dca0d8d0392da34c50db
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include "../git-compat-util.h"
6 unsigned int _CRT_fmode = _O_BINARY;
8 int readlink(const char *path, char *buf, size_t bufsiz)
10 errno = ENOSYS;
11 return -1;
14 int symlink(const char *oldpath, const char *newpath)
16 errno = ENOSYS;
17 return -1;
20 int fchmod(int fildes, mode_t mode)
22 errno = EBADF;
23 return -1;
26 int lstat(const char *file_name, struct stat *buf)
28 int namelen;
29 static char alt_name[PATH_MAX];
31 if (!stat(file_name, buf))
32 return 0;
34 /* if file_name ended in a '/', Windows returned ENOENT;
35 * try again without trailing slashes
37 if (errno != ENOENT)
38 return -1;
39 namelen = strlen(file_name);
40 if (namelen && file_name[namelen-1] != '/')
41 return -1;
42 while (namelen && file_name[namelen-1] == '/')
43 --namelen;
44 if (!namelen || namelen >= PATH_MAX)
45 return -1;
46 memcpy(alt_name, file_name, namelen);
47 alt_name[namelen] = 0;
48 return stat(alt_name, buf);
51 /* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */
52 int socketpair(int d, int type, int protocol, int sv[2])
54 return -1;
56 int syslog(int type, char *bufp, ...)
58 return -1;
60 unsigned int alarm(unsigned int seconds)
62 return 0;
64 #include <winsock2.h>
65 int fork()
67 return -1;
70 int kill(pid_t pid, int sig)
72 return -1;
74 unsigned int sleep (unsigned int __seconds)
76 Sleep(__seconds*1000);
77 return 0;
79 const char *inet_ntop(int af, const void *src,
80 char *dst, size_t cnt)
82 return NULL;
84 int mkstemp (char *__template)
86 char *filename = mktemp(__template);
87 if (filename == NULL)
88 return -1;
89 return open(filename, O_RDWR | O_CREAT, 0600);
92 int gettimeofday(struct timeval *tv, void *tz)
94 extern time_t my_mktime(struct tm *tm);
95 SYSTEMTIME st;
96 struct tm tm;
97 GetSystemTime(&st);
98 tm.tm_year = st.wYear-1900;
99 tm.tm_mon = st.wMonth-1;
100 tm.tm_mday = st.wDay;
101 tm.tm_hour = st.wHour;
102 tm.tm_min = st.wMinute;
103 tm.tm_sec = st.wSecond;
104 tv->tv_sec = my_mktime(&tm);
105 if (tv->tv_sec < 0)
106 return -1;
107 tv->tv_usec = st.wMilliseconds*1000;
108 return 0;
111 int pipe(int filedes[2])
113 int fd;
114 HANDLE h[2], parent;
116 if (_pipe(filedes, 8192, 0) < 0)
117 return -1;
119 parent = GetCurrentProcess();
121 if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[0]),
122 parent, &h[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) {
123 close(filedes[0]);
124 close(filedes[1]);
125 return -1;
127 if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[1]),
128 parent, &h[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) {
129 close(filedes[0]);
130 close(filedes[1]);
131 CloseHandle(h[0]);
132 return -1;
134 fd = _open_osfhandle(h[0], O_NOINHERIT);
135 if (fd < 0) {
136 close(filedes[0]);
137 close(filedes[1]);
138 CloseHandle(h[0]);
139 CloseHandle(h[1]);
140 return -1;
142 close(filedes[0]);
143 filedes[0] = fd;
144 fd = _open_osfhandle(h[1], O_NOINHERIT);
145 if (fd < 0) {
146 close(filedes[0]);
147 close(filedes[1]);
148 CloseHandle(h[1]);
149 return -1;
151 close(filedes[1]);
152 filedes[1] = fd;
153 return 0;
156 int poll(struct pollfd *ufds, unsigned int nfds, int timeout)
158 return -1;
161 #include <time.h>
163 struct tm *gmtime_r(const time_t *timep, struct tm *result)
165 memcpy(result, gmtime(timep), sizeof(struct tm));
166 return result;
169 struct tm *localtime_r(const time_t *timep, struct tm *result)
171 memcpy(result, localtime(timep), sizeof(struct tm));
172 return result;
175 #undef getcwd
176 char *mingw_getcwd(char *pointer, int len)
178 char *ret = getcwd(pointer, len);
179 if (!ret)
180 return ret;
181 if (pointer[0] != 0 && pointer[1] == ':') {
182 int i;
183 for (i = 2; pointer[i]; i++)
184 /* Thanks, Bill. You'll burn in hell for that. */
185 if (pointer[i] == '\\')
186 pointer[i] = '/';
188 return ret;
191 void sync(void)
195 void openlog(const char *ident, int option, int facility)
199 static const char *quote_arg(const char *arg)
201 /* count chars to quote */
202 int len = 0, n = 0;
203 int force_quotes = 0;
204 char *q, *d;
205 const char *p = arg;
206 while (*p) {
207 if (isspace(*p))
208 force_quotes = 1;
209 else if (*p == '"' || *p == '\\')
210 n++;
211 len++;
212 p++;
214 if (!force_quotes && n == 0)
215 return arg;
217 /* insert \ where necessary */
218 d = q = xmalloc(len+n+3);
219 *d++ = '"';
220 while (*arg) {
221 if (*arg == '"' || *arg == '\\')
222 *d++ = '\\';
223 *d++ = *arg++;
225 *d++ = '"';
226 *d++ = 0;
227 return q;
230 void quote_argv(const char **dst, const char **src)
232 while (*src)
233 *dst++ = quote_arg(*src++);
234 *dst = NULL;
237 const char *parse_interpreter(const char *cmd)
239 static char buf[100];
240 char *p, *opt;
241 int n, fd;
243 /* don't even try a .exe */
244 n = strlen(cmd);
245 if (n >= 4 && !strcasecmp(cmd+n-4, ".exe"))
246 return NULL;
248 fd = open(cmd, O_RDONLY);
249 if (fd < 0)
250 return NULL;
251 n = read(fd, buf, sizeof(buf)-1);
252 close(fd);
253 if (n < 4) /* at least '#!/x' and not error */
254 return NULL;
256 if (buf[0] != '#' || buf[1] != '!')
257 return NULL;
258 buf[n] = '\0';
259 p = strchr(buf, '\n');
260 if (!p)
261 return NULL;
263 *p = '\0';
264 if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\')))
265 return NULL;
266 /* strip options */
267 if ((opt = strchr(p+1, ' ')))
268 *opt = '\0';
269 return p+1;
272 static int try_shell_exec(const char *cmd, const char **argv, const char **env)
274 const char **sh_argv;
275 int n;
276 const char *interpr = parse_interpreter(cmd);
277 if (!interpr)
278 return 0;
281 * expand
282 * git-foo args...
283 * into
284 * sh git-foo args...
286 for (n = 0; argv[n];) n++;
287 sh_argv = xmalloc((n+2)*sizeof(char*));
288 sh_argv[0] = interpr;
289 sh_argv[1] = quote_arg(cmd);
290 quote_argv(&sh_argv[2], &argv[1]);
291 n = spawnvpe(_P_WAIT, interpr, sh_argv, env);
292 if (n == -1)
293 return 1; /* indicate that we tried but failed */
294 exit(n);
297 void mingw_execve(const char *cmd, const char **argv, const char **env)
299 /* check if git_command is a shell script */
300 if (!try_shell_exec(cmd, argv, env)) {
301 int ret = spawnve(_P_WAIT, cmd, argv, env);
302 if (ret != -1)
303 exit(ret);
307 int mingw_socket(int domain, int type, int protocol)
309 SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0);
310 if (s == INVALID_SOCKET) {
312 * WSAGetLastError() values are regular BSD error codes
313 * biased by WSABASEERR.
314 * However, strerror() does not know about networking
315 * specific errors, which are values beginning at 38 or so.
316 * Therefore, we choose to leave the biased error code
317 * in errno so that _if_ someone looks up the code somewhere,
318 * then it is at least the number that are usually listed.
320 errno = WSAGetLastError();
321 return -1;
323 return s;