1 #pragma prototyped noticed
2 
3 /*
4  * workarounds to bring the native interface close to posix and x/open
5  */
6 
7 #if defined(__STDPP__directive) && defined(__STDPP__hide)
8 __STDPP__directive pragma pp:hide utime utimes
9 #else
10 #define utime		______utime
11 #define utimes		______utimes
12 #endif
13 
14 #include <ast.h>
15 #include <error.h>
16 #include <tm.h>
17 
18 #include "FEATURE/omitted"
19 
20 #undef	OMITTED
21 
22 #if _win32_botch
23 
24 #define	OMITTED	1
25 
26 #include <ls.h>
27 #include <utime.h>
28 
29 #if __CYGWIN__
30 #include <ast_windows.h>
31 #if _win32_botch_execve || _lib_spawn_mode
32 #define CONVERT		1
33 #endif
34 #endif
35 
36 #if defined(__STDPP__directive) && defined(__STDPP__hide)
37 __STDPP__directive pragma pp:nohide utime utimes
38 #else
39 #undef	utime
40 #undef	utimes
41 #endif
42 
43 #ifndef MAX_PATH
44 #define MAX_PATH	PATH_MAX
45 #endif
46 
47 /*
48  * these workarounds assume each system call foo() has a _foo() entry
49  * which is true for __CYGWIN__ and __EMX__ (both gnu based)
50  *
51  * the workarounds handle:
52  *
53  *	(1) .exe suffix inconsistencies
54  *	(2) /bin/sh reference in execve() and spawnve()
55  *	(3) bogus getpagesize() return values
56  *	(4) a fork() bug that screws up shell fork()+script
57  *
58  * NOTE: Not all workarounds can be handled by unix syscall intercepts.
59  *	 In particular, { ksh nmake } have workarounds for case-ignorant
60  *	 filesystems and { libast } has workarounds for win32 locale info.
61  */
62 
63 #undef _pathconf
64 #undef pathconf
65 #undef stat
66 
67 extern int		_access(const char*, int);
68 extern unsigned int	_alarm(unsigned int);
69 extern int		_chmod(const char*, mode_t);
70 extern int		_close(int);
71 extern pid_t		_execve(const char*, char* const*, char* const*);
72 extern uid_t		_getuid(void);
73 extern int		_link(const char*, const char*);
74 extern int		_open(const char*, int, ...);
75 extern long		_pathconf(const char*, int);
76 extern ssize_t		_read(int, void*, size_t);
77 extern int		_rename(const char*, const char*);
78 extern pid_t		_spawnve(int, const char*, char* const*, char* const*);
79 extern int		_stat(const char*, struct stat*);
80 extern int		_unlink(const char*);
81 extern int		_utime(const char*, const struct utimbuf*);
82 extern int		_utimes(const char*, const struct timeval*);
83 extern ssize_t		_write(int, const void*, size_t);
84 
85 #if defined(__EXPORT__)
86 #define extern	__EXPORT__
87 #endif
88 
89 #if _win32_botch_access
90 #define sysaccess		_access
91 #else
92 #define sysaccess		access
93 #endif
94 #if _win32_botch_alarm
95 #define sysalarm		_alarm
96 #else
97 #define sysalarm		alarm
98 #endif
99 #if _win32_botch_chmod
100 #define syschmod		_chmod
101 #else
102 #define syschmod		chmod
103 #endif
104 #if _win32_botch_copy
105 #define sysclose		_close
106 #else
107 #define sysclose		close
108 #endif
109 #if _win32_botch_execve || _lib_spawn_mode
110 #define sysexecve		_execve
111 #else
112 #define sysexecve		execve
113 #endif
114 #if CONVERT
115 #define sysgetuid		_getuid
116 #else
117 #define sysgetuid		getuid
118 #endif
119 #if _win32_botch_link
120 #define syslink			_link
121 #else
122 #define syslink			link
123 #endif
124 #if _win32_botch_open || _win32_botch_copy
125 #define sysopen			_open
126 #else
127 #define sysopen			open
128 #endif
129 #if _win32_botch_pathconf
130 #define syspathconf		_pathconf
131 #else
132 #define syspathconf		pathconf
133 #endif
134 #define sysread			_read
135 #if _win32_botch_rename
136 #define sysrename		_rename
137 #else
138 #define sysrename		rename
139 #endif
140 #if _lib_spawn_mode
141 #define sysspawnve		_spawnve
142 #else
143 #define sysspawnve		spawnve
144 #endif
145 #if _win32_botch_stat
146 #define sysstat			_stat
147 #else
148 #define sysstat			stat
149 #endif
150 #if _win32_botch_truncate
151 #define systruncate		_truncate
152 #else
153 #define systruncate		truncate
154 #endif
155 #if _win32_botch_unlink
156 #define sysunlink		_unlink
157 #else
158 #define sysunlink		unlink
159 #endif
160 #if _win32_botch_utime
161 #define sysutime		_utime
162 #define sysutimes		_utimes
163 #else
164 #define sysutime		utime
165 #define sysutimes		utimes
166 #endif
167 #if _win32_botch_copy
168 #define syswrite		_write
169 #else
170 #define syswrite		write
171 #endif
172 
173 static char*
suffix(register const char * path)174 suffix(register const char* path)
175 {
176 	register const char*	s = path + strlen(path);
177 	register int		c;
178 
179 	while (s > path)
180 		if ((c = *--s) == '.')
181 			return (char*)s + 1;
182 		else if (c == '/' || c == '\\')
183 			break;
184 	return 0;
185 }
186 
187 static int
execrate(const char * path,char * buf,int size,int physical)188 execrate(const char* path, char* buf, int size, int physical)
189 {
190 	char*	s;
191 	int	n;
192 	int	oerrno;
193 
194 	if (suffix(path))
195 		return 0;
196 	oerrno = errno;
197 	if (physical || strlen(path) >= size || !(s = pathcanon(strcpy(buf, path), size, PATH_PHYSICAL|PATH_DOTDOT|PATH_EXISTS)))
198 		snprintf(buf, size, "%s.exe", path);
199 	else if (!suffix(buf) && ((buf + size) - s) >= 4)
200 		strcpy(s, ".exe");
201 	errno = oerrno;
202 	return 1;
203 }
204 
205 /*
206  * return 0 if path is magic, -1 otherwise
207  * ux!=0 set to 1 if path is unix executable
208  * ux!=0 also retains errno for -1 return
209  */
210 
211 static int
magic(const char * path,int * ux)212 magic(const char* path, int* ux)
213 {
214 	int		fd;
215 	int		r;
216 	int		n;
217 	int		m;
218 	int		oerrno;
219 #if CONVERT
220 	unsigned char	buf[512];
221 #else
222 	unsigned char	buf[2];
223 #endif
224 
225 	oerrno = errno;
226 	if ((fd = sysopen(path, O_RDONLY, 0)) >= 0)
227 	{
228 #if CONVERT
229 		if (ux)
230 			n = sizeof(buf);
231 		else
232 #endif
233 			n = 2;
234 		r = (m = sysread(fd, buf, n)) >= 2 && (buf[1] == 0x5a && (buf[0] == 0x4c || buf[0] == 0x4d) || ux && buf[0] == '#' && buf[1] == '!' && (*ux = 1) && !(ux = 0)) ? 0 : -1;
235 		sysclose(fd);
236 		if (ux)
237 		{
238 			if (r)
239 				oerrno = ENOEXEC;
240 			else if (m > 61 && (n = buf[60] | (buf[61]<<8) + 92) < (m - 1))
241 				*ux = (buf[n] | (buf[n+1]<<8)) == 3;
242 			else
243 				*ux = 0;
244 		}
245 	}
246 	else if (!ux)
247 		r = -1;
248 	else if (errno == ENOENT)
249 	{
250 		oerrno = errno;
251 		r = -1;
252 	}
253 	else
254 	{
255 		r = 0;
256 		*ux = 0;
257 	}
258 	errno = oerrno;
259 	return r;
260 }
261 
262 #if _win32_botch_access
263 
264 extern int
access(const char * path,int op)265 access(const char* path, int op)
266 {
267 	int	r;
268 	int	oerrno;
269 	char	buf[PATH_MAX];
270 
271 	oerrno = errno;
272 	if ((r = sysaccess(path, op)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
273 	{
274 		errno = oerrno;
275 		r = sysaccess(buf, op);
276 	}
277 	return r;
278 }
279 
280 #endif
281 
282 #if _win32_botch_alarm
283 
284 extern unsigned int
alarm(unsigned int s)285 alarm(unsigned int s)
286 {
287 	unsigned int		n;
288 	unsigned int		r;
289 
290 	static unsigned int	a;
291 
292 	n = (unsigned int)time(NiL);
293 	if (a <= n)
294 		r = 0;
295 	else
296 		r = a - n;
297 	a = n + s - 1;
298 	(void)sysalarm(s);
299 	return r;
300 }
301 
302 #endif
303 
304 #if _win32_botch_chmod
305 
306 extern int
chmod(const char * path,mode_t mode)307 chmod(const char* path, mode_t mode)
308 {
309 	int	r;
310 	int	oerrno;
311 	char	buf[PATH_MAX];
312 
313 	if ((r = syschmod(path, mode)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
314 	{
315 		errno = oerrno;
316 		return syschmod(buf, mode);
317 	}
318 	if (!(r = syschmod(path, mode)) &&
319 	    (mode & (S_IXUSR|S_IXGRP|S_IXOTH)) &&
320 	    !suffix(path) &&
321 	    (strlen(path) + 4) < sizeof(buf))
322 	{
323 		oerrno = errno;
324 		if (!magic(path, NiL))
325 		{
326 			snprintf(buf, sizeof(buf), "%s.exe", path);
327 			sysrename(path, buf);
328 		}
329 		errno = oerrno;
330 	}
331 	return r;
332 }
333 
334 #endif
335 
336 #if _win32_botch_execve || _lib_spawn_mode
337 
338 #if _lib_spawn_mode
339 
340 /*
341  * can anyone get const prototype args straight?
342  */
343 
344 #define execve		______execve
345 #define spawnve		______spawnve
346 
347 #include <process.h>
348 
349 #undef	execve
350 #undef	spawnve
351 
352 #endif
353 
354 #if CONVERT
355 
356 /*
357  * this intercept converts dos env vars to unix
358  * we'd rather intercept main but can't twist cc to do it
359  * getuid() gets ksh to do the right thing and
360  * that's our main concern
361  *
362  *	DOSPATHVARS='a b c'	convert { a b c }
363  */
364 
365 static int		convertinit;
366 
367 /*
368  * convertvars[0] names the list of env var names
369  * convertvars[i] are not converted
370  */
371 
372 static const char*	convertvars[] = { "DOSPATHVARS", "PATH" };
373 
374 static int
convert(register const char * d,const char * s)375 convert(register const char* d, const char* s)
376 {
377 	register const char*	t;
378 	register const char*	v;
379 	int			i;
380 
381 	for (i = 0; i < elementsof(convertvars); i++)
382 	{
383 		for (v = convertvars[i], t = s; *t && *t == *v; t++, v++);
384 		if (*t == '=' && *v == 0)
385 			return 0;
386 	}
387 	for (;;)
388 	{
389 		while (*d == ' ' || *d == '\t')
390 			d++;
391 		if (!*d)
392 			break;
393 		for (t = s; *t && *t == *d; d++, t++);
394 		if (*t == '=' && (*d == ' ' || *d == '\t' || *d == 0))
395 			return t - s + 1;
396 		while (*d && *d != ' ' && *d != '\t')
397 			d++;
398 	}
399 	return 0;
400 }
401 
402 uid_t
getuid(void)403 getuid(void)
404 {
405 	register char*		d;
406 	register char*		s;
407 	register char*		t;
408 	register char**		e;
409 	int			n;
410 	int			m;
411 
412 	if (!convertinit++ && (d = getenv(convertvars[0])))
413 		for (e = environ; s = *e; e++)
414 			if ((n = convert(d, s)) && (m = cygwin_win32_to_posix_path_list_buf_size(s + n)) > 0)
415 			{
416 				if (!(t = malloc(n + m + 1)))
417 					break;
418 				*e = t;
419 				memcpy(t, s, n);
420 				cygwin_win32_to_posix_path_list(s + n, t + n);
421 			}
422 	return sysgetuid();
423 }
424 
425 #endif
426 
427 #ifndef _P_OVERLAY
428 #define _P_OVERLAY	(-1)
429 #endif
430 
431 #define DEBUG		1
432 
433 static pid_t
runve(int mode,const char * path,char * const * argv,char * const * envv)434 runve(int mode, const char* path, char* const* argv, char* const* envv)
435 {
436 	register char*	s;
437 	register char**	p;
438 	register char**	v;
439 
440 	void*		m1;
441 	void*		m2;
442 	pid_t		pid;
443 	int		oerrno;
444 	int		ux;
445 	int		n;
446 #if defined(_P_DETACH) && defined(_P_NOWAIT)
447 	int		pgrp;
448 #endif
449 #if CONVERT
450 	char*		d;
451 	char*		t;
452 	int		m;
453 #endif
454 	struct stat	st;
455 	char		buf[PATH_MAX];
456 	char		tmp[PATH_MAX];
457 
458 #if DEBUG
459 	static int	trace;
460 #endif
461 
462 #if defined(_P_DETACH) && defined(_P_NOWAIT)
463 	if (mode == _P_DETACH)
464 	{
465 		/*
466 		 * 2004-02-29 cygwin _P_DETACH is useless:
467 		 *	spawn*() returns 0 instead of the spawned pid
468 		 *	spawned { pgid sid } are the same as the parent
469 		 */
470 
471 		mode = _P_NOWAIT;
472 		pgrp = 1;
473 	}
474 	else
475 		pgrp = 0;
476 #endif
477 	if (!envv)
478 		envv = (char* const*)environ;
479 	m1 = m2 = 0;
480 	oerrno = errno;
481 #if DEBUG
482 	if (!trace)
483 		trace = (s = getenv("_AST_exec_trace")) ? *s : 'n';
484 #endif
485 	if (execrate(path, buf, sizeof(buf), 0))
486 	{
487 		if (!sysstat(buf, &st))
488 			path = (const char*)buf;
489 		else
490 			errno = oerrno;
491 	}
492 	if (path != (const char*)buf && sysstat(path, &st))
493 		return -1;
494 	if (!S_ISREG(st.st_mode) || !(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
495 	{
496 		errno = EACCES;
497 		return -1;
498 	}
499 	if (magic(path, &ux))
500 	{
501 #if _CYGWIN_fork_works
502 		errno = ENOEXEC;
503 		return -1;
504 #else
505 		ux = 1;
506 		p = (char**)argv;
507 		while (*p++);
508 		if (!(v = (char**)malloc((p - (char**)argv + 2) * sizeof(char*))))
509 		{
510 			errno = EAGAIN;
511 			return -1;
512 		}
513 		m1 = v;
514 		p = v;
515 		*p++ = (char*)path;
516 		*p++ = (char*)path;
517 		path = (const char*)pathshell();
518 		if (*argv)
519 			argv++;
520 		while (*p++ = (char*)*argv++);
521 		argv = (char* const*)v;
522 #endif
523 	}
524 
525 	/*
526 	 * the win32 dll search order is
527 	 *	(1) the directory of path
528 	 *	(2) .
529 	 *	(3) /c/(WINNT|WINDOWS)/system32 /c/(WINNT|WINDOWS)
530 	 *	(4) the directories on $PATH
531 	 * there are no cygwin dlls in (3), so if (1) and (2) fail
532 	 * to produce the required dlls its up to (4)
533 	 *
534 	 * the standard allows PATH to be anything once the path
535 	 * to an executable is determined; this code ensures that PATH
536 	 * contains /bin so that at least the cygwin dll, required
537 	 * by all cygwin executables, will be found
538 	 */
539 
540 	if (p = (char**)envv)
541 	{
542 		n = 1;
543 		while (s = *p++)
544 			if (strneq(s, "PATH=", 5))
545 			{
546 				s += 5;
547 				do
548 				{
549 					s = pathcat(s, ':', NiL, "", tmp, sizeof(tmp));
550 					if (streq(tmp, "/usr/bin/") || streq(tmp, "/bin/"))
551 					{
552 						n = 0;
553 						break;
554 					}
555 				} while (s);
556 				if (n)
557 				{
558 					n = 0;
559 					snprintf(tmp, sizeof(tmp), "%s:/bin", *(p - 1));
560 					*(p - 1) = tmp;
561 				}
562 				break;
563 			}
564 		if (n)
565 		{
566 			n = p - (char**)envv + 1;
567 			p = (char**)envv;
568 			if (v = (char**)malloc(n * sizeof(char*)))
569 			{
570 				m2 = v;
571 				envv = (char* const*)v;
572 				*v++ = strcpy(tmp, "PATH=/bin");
573 				while (*v++ = *p++);
574 			}
575 		}
576 #if CONVERT
577 		if (!ux && (d = getenv(convertvars[0])))
578 			for (p = (char**)envv; s = *p; p++)
579 				if ((n = convert(d, s)) && (m = cygwin_posix_to_win32_path_list_buf_size(s + n)) > 0)
580 				{
581 					if (!(t = malloc(n + m + 1)))
582 						break;
583 					*p = t;
584 					memcpy(t, s, n);
585 					cygwin_posix_to_win32_path_list(s + n, t + n);
586 				}
587 #endif
588 	}
589 
590 #if DEBUG
591 	if (trace == 'a' || trace == 'e')
592 	{
593 		sfprintf(sfstderr, "%s %s [", mode == _P_OVERLAY ? "_execve" : "_spawnve", path);
594 		for (n = 0; argv[n]; n++)
595 			sfprintf(sfstderr, " '%s'", argv[n]);
596 		if (trace == 'e')
597 		{
598 			sfprintf(sfstderr, " ] [");
599 			for (n = 0; envv[n]; n++)
600 				sfprintf(sfstderr, " '%s'", envv[n]);
601 		}
602 		sfprintf(sfstderr, " ]\n");
603 		sfsync(sfstderr);
604 	}
605 #endif
606 #if _lib_spawn_mode
607 	if (mode != _P_OVERLAY)
608 	{
609 		pid = sysspawnve(mode, path, argv, envv);
610 #if defined(_P_DETACH) && defined(_P_NOWAIT)
611 		if (pid > 0 && pgrp)
612 			setpgid(pid, 0);
613 #endif
614 	}
615 	else
616 #endif
617 	{
618 #if defined(_P_DETACH) && defined(_P_NOWAIT)
619 		if (pgrp)
620 			setpgid(0, 0);
621 #endif
622 		pid = sysexecve(path, argv, envv);
623 	}
624 	if (m1)
625 		free(m1);
626 	if (m2)
627 		free(m2);
628 	return pid;
629 }
630 
631 #if _win32_botch_execve
632 
633 extern pid_t
execve(const char * path,char * const * argv,char * const * envv)634 execve(const char* path, char* const* argv, char* const* envv)
635 {
636 	return runve(_P_OVERLAY, path, argv, envv);
637 }
638 
639 #endif
640 
641 #if _lib_spawn_mode
642 
643 extern pid_t
spawnve(int mode,const char * path,char * const * argv,char * const * envv)644 spawnve(int mode, const char* path, char* const* argv, char* const* envv)
645 {
646 	return runve(mode, path, argv, envv);
647 }
648 
649 #endif
650 
651 #endif
652 
653 #if _win32_botch_getpagesize
654 
655 extern size_t
getpagesize(void)656 getpagesize(void)
657 {
658 	return 64 * 1024;
659 }
660 
661 #endif
662 
663 #if _win32_botch_link
664 
665 extern int
link(const char * fp,const char * tp)666 link(const char* fp, const char* tp)
667 {
668 	int	r;
669 	int	oerrno;
670 	char	fb[PATH_MAX];
671 	char	tb[PATH_MAX];
672 
673 	oerrno = errno;
674 	if ((r = syslink(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1))
675 	{
676 		if (execrate(tp, tb, sizeof(tb), 1))
677 			tp = tb;
678 		errno = oerrno;
679 		r = syslink(fb, tp);
680 	}
681 	return r;
682 }
683 
684 #endif
685 
686 #if _win32_botch_open || _win32_botch_copy
687 
688 #if _win32_botch_copy
689 
690 /*
691  * this should intercept the important cases
692  * dup*() and exec*() fd's will not be intercepted
693  */
694 
695 typedef struct Exe_test_s
696 {
697 	int		test;
698 	ino_t		ino;
699 	char		path[PATH_MAX];
700 } Exe_test_t;
701 
702 static Exe_test_t*	exe[16];
703 
704 extern int
close(int fd)705 close(int fd)
706 {
707 	int		r;
708 	int		oerrno;
709 	struct stat	st;
710 	char		buf[PATH_MAX];
711 
712 	if (fd >= 0 && fd < elementsof(exe) && exe[fd])
713 	{
714 		r = exe[fd]->test;
715 		exe[fd]->test = 0;
716 		if (r > 0 && !fstat(fd, &st) && st.st_ino == exe[fd]->ino)
717 		{
718 			if (r = sysclose(fd))
719 				return r;
720 			oerrno = errno;
721 			if (!stat(exe[fd]->path, &st) && st.st_ino == exe[fd]->ino)
722 			{
723 				snprintf(buf, sizeof(buf), "%s.exe", exe[fd]->path);
724 				sysrename(exe[fd]->path, buf);
725 			}
726 			errno = oerrno;
727 			return 0;
728 		}
729 	}
730 	return sysclose(fd);
731 }
732 
733 extern ssize_t
write(int fd,const void * buf,size_t n)734 write(int fd, const void* buf, size_t n)
735 {
736 	if (fd >= 0 && fd < elementsof(exe) && exe[fd] && exe[fd]->test < 0)
737 		exe[fd]->test = n >= 2 && ((unsigned char*)buf)[1] == 0x5a && (((unsigned char*)buf)[0] == 0x4c || ((unsigned char*)buf)[0] == 0x4d) && !lseek(fd, (off_t)0, SEEK_CUR);
738 	return syswrite(fd, buf, n);
739 }
740 
741 #endif
742 
743 extern int
open(const char * path,int flags,...)744 open(const char* path, int flags, ...)
745 {
746 	int		fd;
747 	int		mode;
748 	int		oerrno;
749 	char		buf[PATH_MAX];
750 #if _win32_botch_copy
751 	struct stat	st;
752 #endif
753 	va_list		ap;
754 
755 	va_start(ap, flags);
756 	mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
757 	oerrno = errno;
758 	fd = sysopen(path, flags, mode);
759 #if _win32_botch_open
760 	if (fd < 0 && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
761 	{
762 		errno = oerrno;
763 		fd = sysopen(buf, flags, mode);
764 	}
765 #endif
766 #if _win32_botch_copy
767 	if (fd >= 0 && fd < elementsof(exe) && strlen(path) < PATH_MAX &&
768 	    (flags & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC) && (mode & 0111))
769 	{
770 		if (!suffix(path) && !fstat(fd, &st) && (exe[fd] || (exe[fd] = (Exe_test_t*)malloc(sizeof(Exe_test_t)))))
771 		{
772 			exe[fd]->test = -1;
773 			exe[fd]->ino = st.st_ino;
774 			strcpy(exe[fd]->path, path);
775 		}
776 		errno = oerrno;
777 	}
778 #endif
779 	va_end(ap);
780 	return fd;
781 }
782 
783 #endif
784 
785 #if _win32_botch_pathconf
786 
787 extern long
pathconf(const char * path,int op)788 pathconf(const char* path, int op)
789 {
790 	if (sysaccess(path, F_OK))
791 		return -1;
792 	return syspathconf(path, op);
793 }
794 
795 #endif
796 
797 #if _win32_botch_rename
798 
799 extern int
rename(const char * fp,const char * tp)800 rename(const char* fp, const char* tp)
801 {
802 	int	r;
803 	int	oerrno;
804 	char	fb[PATH_MAX];
805 	char	tb[PATH_MAX];
806 
807 	oerrno = errno;
808 	if ((r = sysrename(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1))
809 	{
810 		if (execrate(tp, tb, sizeof(tb), 1))
811 			tp = tb;
812 		errno = oerrno;
813 		r = sysrename(fb, tp);
814 	}
815 	return r;
816 }
817 
818 #endif
819 
820 #if _win32_botch_stat
821 
822 extern int
stat(const char * path,struct stat * st)823 stat(const char* path, struct stat* st)
824 {
825 	int	r;
826 	int	oerrno;
827 	char	buf[PATH_MAX];
828 
829 	oerrno = errno;
830 	if ((r = sysstat(path, st)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
831 	{
832 		errno = oerrno;
833 		r = sysstat(buf, st);
834 	}
835 	return r;
836 }
837 
838 #endif
839 
840 #if _win32_botch_truncate
841 
842 extern int
truncate(const char * path,off_t offset)843 truncate(const char* path, off_t offset)
844 {
845 	int	r;
846 	int	oerrno;
847 	char	buf[PATH_MAX];
848 
849 	oerrno = errno;
850 	if ((r = systruncate(path, offset)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
851 	{
852 		errno = oerrno;
853 		r = systruncate(buf, offset);
854 	}
855 	return r;
856 }
857 
858 #endif
859 
860 #if _win32_botch_unlink
861 
862 extern int
unlink(const char * path)863 unlink(const char* path)
864 {
865 	int		r;
866 	int		drive;
867 	int		mask;
868 	int		suffix;
869 	int		stop;
870 	int		oerrno;
871 	unsigned long	base;
872 	char		buf[PATH_MAX];
873 	char		tmp[MAX_PATH];
874 
875 #define DELETED_DIR_1	7
876 #define DELETED_DIR_2	16
877 
878 	static char	deleted[] = "%c:\\temp\\.deleted\\%08x.%03x";
879 
880 	static int	count = 0;
881 
882 #if __CYGWIN__
883 
884 	DWORD		fattr = FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE;
885 	DWORD		share = FILE_SHARE_DELETE;
886 	HANDLE		hp;
887 	struct stat	st;
888 	char		nat[MAX_PATH];
889 
890 	oerrno = errno;
891 	if (lstat(path, &st) || !S_ISREG(st.st_mode))
892 		goto try_unlink;
893 	cygwin_conv_to_full_win32_path(path, nat);
894 	if (!strncasecmp(nat + 1, ":\\temp\\", 7))
895 		goto try_unlink;
896 	drive = nat[0];
897 	path = (const char*)nat;
898 	for (;;)
899 	{
900 		hp = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL);
901 		if (hp != INVALID_HANDLE_VALUE)
902 		{
903 			CloseHandle(hp);
904 			errno = oerrno;
905 			return 0;
906 		}
907 		if (GetLastError() != ERROR_FILE_NOT_FOUND)
908 			break;
909 		if (path == (const char*)buf || !execrate(path, buf, sizeof(buf), 1))
910 		{
911 			errno = ENOENT;
912 			return -1;
913 		}
914 		path = (const char*)buf;
915 	}
916 #else
917 	if (sysaccess(path, 0))
918 #if _win32_botch_access
919 	{
920 		if (errno != ENOENT || !execrate(path, buf, sizeof(buf), 1) || sysaccess(buf, 0))
921 			return -1;
922 		path = (const char*)buf;
923 	}
924 #else
925 		return -1;
926 #endif
927 	drive = 'C':
928 #endif
929 
930 	/*
931 	 * rename to a `deleted' path just in case the file is open
932 	 * otherwise directory readers may choke on phantom entries
933 	 */
934 
935 	base = ((getuid() & 0xffff) << 16) | (time(NiL) & 0xffff);
936 	suffix = (getpid() & 0xfff) + count++;
937 	snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix);
938 	if (!sysrename(path, tmp))
939 	{
940 		path = (const char*)tmp;
941 		goto try_delete;
942 	}
943 	if (errno != ENOTDIR && errno != ENOENT)
944 		goto try_unlink;
945 	tmp[DELETED_DIR_2] = 0;
946 	if (sysaccess(tmp, 0))
947 	{
948 		mask = umask(0);
949 		tmp[DELETED_DIR_1] = 0;
950 		if (sysaccess(tmp, 0) && mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO))
951 		{
952 			umask(mask);
953 			goto try_unlink;
954 		}
955 		tmp[DELETED_DIR_1] = '\\';
956 		r = mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO);
957 		umask(mask);
958 		if (r)
959 			goto try_unlink;
960 		errno = 0;
961 	}
962 	tmp[DELETED_DIR_2] = '\\';
963 	if (!errno && !sysrename(path, tmp))
964 	{
965 		path = (const char*)tmp;
966 		goto try_delete;
967 	}
968 #if !__CYGWIN__
969 	if (errno == ENOENT)
970 	{
971 #if !_win32_botch_access
972 		if (execrate(path, buf, sizeof(buf), 1) && !sysrename(buf, tmp))
973 			path = (const char*)tmp;
974 #endif
975 		goto try_unlink;
976 	}
977 #endif
978 	stop = suffix;
979 	do
980 	{
981 		snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix);
982 		if (!sysrename(path, tmp))
983 		{
984 			path = (const char*)tmp;
985 			goto try_delete;
986 		}
987 		if (++suffix > 0xfff)
988 			suffix = 0;
989 	} while (suffix != stop);
990  try_delete:
991 #if __CYGWIN__
992 	hp = CreateFile(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL);
993 	if (hp != INVALID_HANDLE_VALUE)
994 	{
995 		CloseHandle(hp);
996 		errno = oerrno;
997 		return 0;
998 	}
999 #endif
1000  try_unlink:
1001 	errno = oerrno;
1002 	return sysunlink(path);
1003 }
1004 
1005 #endif
1006 
1007 #if _win32_botch_utime
1008 
1009 #if __CYGWIN__
1010 
1011 /*
1012  * cygwin refuses to set st_ctime for some operations
1013  * this rejects that refusal
1014  */
1015 
1016 static void
ctime_now(const char * path)1017 ctime_now(const char* path)
1018 {
1019 	HANDLE		hp;
1020 	SYSTEMTIME	st;
1021 	FILETIME	ct;
1022 	WIN32_FIND_DATA	ff;
1023 	struct stat	fs;
1024 	int		oerrno;
1025 	char		tmp[MAX_PATH];
1026 
1027 	if (sysstat(path, &fs) || (fs.st_mode & S_IWUSR) || syschmod(path, (fs.st_mode | S_IWUSR) & S_IPERM))
1028 		fs.st_mode = 0;
1029 	cygwin_conv_to_win32_path(path, tmp);
1030 	hp = CreateFile(tmp, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1031 	if (hp && hp != INVALID_HANDLE_VALUE)
1032 	{
1033 		GetSystemTime(&st);
1034 		SystemTimeToFileTime(&st, &ct);
1035 		SetFileTime(hp, &ct, 0, 0);
1036 		CloseHandle(hp);
1037 	}
1038 	if (fs.st_mode)
1039 		syschmod(path, fs.st_mode & S_IPERM);
1040 	errno = oerrno;
1041 }
1042 
1043 #else
1044 
1045 #define ctime_now(p)
1046 
1047 #endif
1048 
1049 extern int
utimes(const char * path,const struct timeval * ut)1050 utimes(const char* path, const struct timeval* ut)
1051 {
1052 	int	r;
1053 	int	oerrno;
1054 	char	buf[PATH_MAX];
1055 
1056 	oerrno = errno;
1057 	if ((r = sysutimes(path, ut)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
1058 	{
1059 		errno = oerrno;
1060 		r = sysutimes(path = buf, ut);
1061 	}
1062 	if (!r)
1063 		ctime_now(path);
1064 	return r;
1065 }
1066 
1067 extern int
utime(const char * path,const struct utimbuf * ut)1068 utime(const char* path, const struct utimbuf* ut)
1069 {
1070 	int	r;
1071 	int	oerrno;
1072 	char	buf[PATH_MAX];
1073 
1074 	oerrno = errno;
1075 	if ((r = sysutime(path, ut)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
1076 	{
1077 		errno = oerrno;
1078 		r = sysutime(path = buf, ut);
1079 	}
1080 	if (!r)
1081 		ctime_now(path);
1082 	return r;
1083 }
1084 
1085 #endif
1086 
1087 #endif
1088 
1089 /*
1090  * some systems (sun) miss a few functions required by their
1091  * own bsd-like macros
1092  */
1093 
1094 #if !_lib_bzero || defined(bzero)
1095 
1096 #undef	bzero
1097 
1098 void
bzero(void * b,size_t n)1099 bzero(void* b, size_t n)
1100 {
1101 	memset(b, 0, n);
1102 }
1103 
1104 #endif
1105 
1106 #if !_lib_getpagesize || defined(getpagesize)
1107 
1108 #ifndef OMITTED
1109 #define OMITTED	1
1110 #endif
1111 
1112 #undef	getpagesize
1113 
1114 #ifdef	_SC_PAGESIZE
1115 #undef	_AST_PAGESIZE
1116 #define _AST_PAGESIZE	(int)sysconf(_SC_PAGESIZE)
1117 #else
1118 #ifndef _AST_PAGESIZE
1119 #define _AST_PAGESIZE	4096
1120 #endif
1121 #endif
1122 
1123 int
getpagesize()1124 getpagesize()
1125 {
1126 	return _AST_PAGESIZE;
1127 }
1128 
1129 #endif
1130 
1131 #if __CYGWIN__ && defined(__IMPORT__) && defined(__EXPORT__)
1132 
1133 #ifndef OMITTED
1134 #define OMITTED	1
1135 #endif
1136 
1137 /*
1138  * a few _imp__FUNCTION symbols are needed to avoid
1139  * static link multiple definitions
1140  */
1141 
1142 #ifndef strtod
1143 __EXPORT__ double (*_imp__strtod)(const char*, char**) = strtod;
1144 #endif
1145 
1146 #endif
1147 
1148 #ifndef OMITTED
1149 
1150 NoN(omitted)
1151 
1152 #endif
1153