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
67extern int		_access(const char*, int);
68extern unsigned int	_alarm(unsigned int);
69extern int		_chmod(const char*, mode_t);
70extern int		_close(int);
71extern pid_t		_execve(const char*, char* const*, char* const*);
72extern int		_link(const char*, const char*);
73extern int		_open(const char*, int, ...);
74extern long		_pathconf(const char*, int);
75extern ssize_t		_read(int, void*, size_t);
76extern int		_rename(const char*, const char*);
77extern pid_t		_spawnve(int, const char*, char* const*, char* const*);
78extern int		_stat(const char*, struct stat*);
79extern int		_unlink(const char*);
80extern int		_utime(const char*, const struct utimbuf*);
81extern int		_utimes(const char*, const struct timeval*);
82extern ssize_t		_write(int, const void*, size_t);
83
84#if defined(__EXPORT__)
85#define extern	__EXPORT__
86#endif
87
88static char*
89suffix(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
102static int
103execrate(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
126static int
127magic(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
179extern int
180access(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
199extern unsigned int
200alarm(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
221extern int
222chmod(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
280extern uid_t		_getuid(void);
281
282static int		convertinit;
283
284/*
285 * convertvars[0] names the list of env var names
286 * convertvars[i] are not converted
287 */
288
289static const char*	convertvars[] = { "DOSPATHVARS", "PATH" };
290
291static int
292convert(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
319uid_t
320getuid(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
350static pid_t
351runve(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
550extern pid_t
551execve(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
560extern pid_t
561spawnve(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
572extern size_t
573getpagesize(void)
574{
575	return 64 * 1024;
576}
577
578#endif
579
580#if _win32_botch_link
581
582extern int
583link(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
612typedef struct Exe_test_s
613{
614	int		test;
615	ino_t		ino;
616	char		path[PATH_MAX];
617} Exe_test_t;
618
619static Exe_test_t*	exe[16];
620
621extern int
622close(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
650extern ssize_t
651write(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
660extern int
661open(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
704extern long
705pathconf(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
716extern int
717rename(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
739extern int
740stat(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
759extern int
760truncate(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
779extern int
780unlink(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
933static void
934ctime_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
966extern int
967utimes(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
984extern int
985utime(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
1015void
1016bzero(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
1040int
1041getpagesize()
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
1067NoN(omitted)
1068
1069#endif
1070