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