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 uid_t		_getuid(void);
73extern int		_link(const char*, const char*);
74extern int		_open(const char*, int, ...);
75extern long		_pathconf(const char*, int);
76extern ssize_t		_read(int, void*, size_t);
77extern int		_rename(const char*, const char*);
78extern pid_t		_spawnve(int, const char*, char* const*, char* const*);
79extern int		_stat(const char*, struct stat*);
80extern int		_unlink(const char*);
81extern int		_utime(const char*, const struct utimbuf*);
82extern int		_utimes(const char*, const struct timeval*);
83extern 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
173static char*
174suffix(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
187static int
188execrate(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
211static int
212magic(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
264extern int
265access(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
284extern unsigned int
285alarm(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
306extern int
307chmod(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
365static int		convertinit;
366
367/*
368 * convertvars[0] names the list of env var names
369 * convertvars[i] are not converted
370 */
371
372static const char*	convertvars[] = { "DOSPATHVARS", "PATH" };
373
374static int
375convert(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
402uid_t
403getuid(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
433static pid_t
434runve(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
633extern pid_t
634execve(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
643extern pid_t
644spawnve(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
655extern size_t
656getpagesize(void)
657{
658	return 64 * 1024;
659}
660
661#endif
662
663#if _win32_botch_link
664
665extern int
666link(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
695typedef struct Exe_test_s
696{
697	int		test;
698	ino_t		ino;
699	char		path[PATH_MAX];
700} Exe_test_t;
701
702static Exe_test_t*	exe[16];
703
704extern int
705close(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
733extern ssize_t
734write(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
743extern int
744open(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
787extern long
788pathconf(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
799extern int
800rename(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
822extern int
823stat(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
842extern int
843truncate(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
862extern int
863unlink(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
1016static void
1017ctime_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
1049extern int
1050utimes(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
1067extern int
1068utime(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
1098void
1099bzero(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
1123int
1124getpagesize()
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
1150NoN(omitted)
1151
1152#endif
1153