mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Compilers like GCC are capable of optimizing away calls like pow(1,inf), which caused the IEEE compliance feature test within libast to incorrectly succeed on platforms with non-IEEE behavior. This is arguably a bug within GCC, as floating point optimizations should never alter the behavior of code unless IEEE compliance is explicitly disabled via a flag like -ffast-math. Programs in which only some calls to pow are optimized away are liable to severely malfunction. Thanks to Martijn Dekker for pointing this issue out and the kind operators of polarhome.com for permitting me gratis use of their Unix systems. src/lib/libast/comp/omitted.c: - Add IEEE compliant functions that wrap powf, pow, and powl. src/lib/libast/features/float: - Look for powf, pow, and powl in the C library. - For compilers that do the right thing, like the native toolchains of Solaris and UnixWare, use lightweight macros to wrap the pow functions. - Use a volatile function pointer through which to access the C library's pow function in an attempt to defeat code optimization. - For these overzealous compilers, define pow to _ast_pow so that the same technique can be used within the above functions.
1183 lines
22 KiB
C
1183 lines
22 KiB
C
#pragma prototyped noticed
|
|
|
|
/*
|
|
* workarounds to bring the native interface close to posix and x/open
|
|
*/
|
|
|
|
#if defined(__STDPP__directive) && defined(__STDPP__hide)
|
|
__STDPP__directive pragma pp:hide utime utimes
|
|
#else
|
|
#define utime ______utime
|
|
#define utimes ______utimes
|
|
#endif
|
|
|
|
#include <ast.h>
|
|
#include <error.h>
|
|
#include <tm.h>
|
|
|
|
#include "FEATURE/float"
|
|
#include "FEATURE/omitted"
|
|
|
|
#undef OMITTED
|
|
|
|
#if _win32_botch
|
|
|
|
#define OMITTED 1
|
|
|
|
#include <ls.h>
|
|
#include <utime.h>
|
|
|
|
#if __CYGWIN__
|
|
#include <ast_windows.h>
|
|
#if _win32_botch_execve || _lib_spawn_mode
|
|
#define CONVERT 1
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(__STDPP__directive) && defined(__STDPP__hide)
|
|
__STDPP__directive pragma pp:nohide utime utimes
|
|
#else
|
|
#undef utime
|
|
#undef utimes
|
|
#endif
|
|
|
|
#ifndef MAX_PATH
|
|
#define MAX_PATH PATH_MAX
|
|
#endif
|
|
|
|
/*
|
|
* these workarounds assume each system call foo() has a _foo() entry
|
|
* which is true for __CYGWIN__ and __EMX__ (both gnu based)
|
|
*
|
|
* the workarounds handle:
|
|
*
|
|
* (1) .exe suffix inconsistencies
|
|
* (2) /bin/sh reference in execve() and spawnve()
|
|
* (3) bogus getpagesize() return values
|
|
* (4) a fork() bug that screws up shell fork()+script
|
|
*
|
|
* NOTE: Not all workarounds can be handled by unix syscall intercepts.
|
|
* In particular, { ksh nmake } have workarounds for case-ignorant
|
|
* filesystems and { libast } has workarounds for win32 locale info.
|
|
*/
|
|
|
|
#undef _pathconf
|
|
#undef pathconf
|
|
#undef stat
|
|
|
|
extern int _access(const char*, int);
|
|
extern unsigned int _alarm(unsigned int);
|
|
extern int _chmod(const char*, mode_t);
|
|
extern int _close(int);
|
|
extern pid_t _execve(const char*, char* const*, char* const*);
|
|
extern uid_t _getuid(void);
|
|
extern int _link(const char*, const char*);
|
|
extern int _open(const char*, int, ...);
|
|
extern long _pathconf(const char*, int);
|
|
extern ssize_t _read(int, void*, size_t);
|
|
extern int _rename(const char*, const char*);
|
|
extern pid_t _spawnve(int, const char*, char* const*, char* const*);
|
|
extern int _stat(const char*, struct stat*);
|
|
extern int _unlink(const char*);
|
|
extern int _utime(const char*, const struct utimbuf*);
|
|
extern int _utimes(const char*, const struct timeval*);
|
|
extern ssize_t _write(int, const void*, size_t);
|
|
|
|
#if defined(__EXPORT__)
|
|
#define extern __EXPORT__
|
|
#endif
|
|
|
|
#if _win32_botch_access
|
|
#define sysaccess _access
|
|
#else
|
|
#define sysaccess access
|
|
#endif
|
|
#if _win32_botch_alarm
|
|
#define sysalarm _alarm
|
|
#else
|
|
#define sysalarm alarm
|
|
#endif
|
|
#if _win32_botch_chmod
|
|
#define syschmod _chmod
|
|
#else
|
|
#define syschmod chmod
|
|
#endif
|
|
#if _win32_botch_copy
|
|
#define sysclose _close
|
|
#else
|
|
#define sysclose close
|
|
#endif
|
|
#if _win32_botch_execve || _lib_spawn_mode
|
|
#define sysexecve _execve
|
|
#else
|
|
#define sysexecve execve
|
|
#endif
|
|
#if CONVERT
|
|
#define sysgetuid _getuid
|
|
#else
|
|
#define sysgetuid getuid
|
|
#endif
|
|
#if _win32_botch_link
|
|
#define syslink _link
|
|
#else
|
|
#define syslink link
|
|
#endif
|
|
#if _win32_botch_open || _win32_botch_copy
|
|
#define sysopen _open
|
|
#else
|
|
#define sysopen open
|
|
#endif
|
|
#if _win32_botch_pathconf
|
|
#define syspathconf _pathconf
|
|
#else
|
|
#define syspathconf pathconf
|
|
#endif
|
|
#define sysread _read
|
|
#if _win32_botch_rename
|
|
#define sysrename _rename
|
|
#else
|
|
#define sysrename rename
|
|
#endif
|
|
#if _lib_spawn_mode
|
|
#define sysspawnve _spawnve
|
|
#else
|
|
#define sysspawnve spawnve
|
|
#endif
|
|
#if _win32_botch_stat
|
|
#define sysstat _stat
|
|
#else
|
|
#define sysstat stat
|
|
#endif
|
|
#if _win32_botch_truncate
|
|
#define systruncate _truncate
|
|
#else
|
|
#define systruncate truncate
|
|
#endif
|
|
#if _win32_botch_unlink
|
|
#define sysunlink _unlink
|
|
#else
|
|
#define sysunlink unlink
|
|
#endif
|
|
#if _win32_botch_utime
|
|
#define sysutime _utime
|
|
#define sysutimes _utimes
|
|
#else
|
|
#define sysutime utime
|
|
#define sysutimes utimes
|
|
#endif
|
|
#if _win32_botch_copy
|
|
#define syswrite _write
|
|
#else
|
|
#define syswrite write
|
|
#endif
|
|
|
|
static char*
|
|
suffix(register const char* path)
|
|
{
|
|
register const char* s = path + strlen(path);
|
|
register int c;
|
|
|
|
while (s > path)
|
|
if ((c = *--s) == '.')
|
|
return (char*)s + 1;
|
|
else if (c == '/' || c == '\\')
|
|
break;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
execrate(const char* path, char* buf, int size, int physical)
|
|
{
|
|
char* s;
|
|
int n;
|
|
int oerrno;
|
|
|
|
if (suffix(path))
|
|
return 0;
|
|
oerrno = errno;
|
|
if (physical || strlen(path) >= size || !(s = pathcanon(strcpy(buf, path), size, PATH_PHYSICAL|PATH_DOTDOT|PATH_EXISTS)))
|
|
snprintf(buf, size, "%s.exe", path);
|
|
else if (!suffix(buf) && ((buf + size) - s) >= 4)
|
|
strcpy(s, ".exe");
|
|
errno = oerrno;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* return 0 if path is magic, -1 otherwise
|
|
* ux!=0 set to 1 if path is unix executable
|
|
* ux!=0 also retains errno for -1 return
|
|
*/
|
|
|
|
static int
|
|
magic(const char* path, int* ux)
|
|
{
|
|
int fd;
|
|
int r;
|
|
int n;
|
|
int m;
|
|
int oerrno;
|
|
#if CONVERT
|
|
unsigned char buf[512];
|
|
#else
|
|
unsigned char buf[2];
|
|
#endif
|
|
|
|
oerrno = errno;
|
|
if ((fd = sysopen(path, O_RDONLY, 0)) >= 0)
|
|
{
|
|
#if CONVERT
|
|
if (ux)
|
|
n = sizeof(buf);
|
|
else
|
|
#endif
|
|
n = 2;
|
|
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;
|
|
sysclose(fd);
|
|
if (ux)
|
|
{
|
|
if (r)
|
|
oerrno = ENOEXEC;
|
|
else if (m > 61 && (n = buf[60] | (buf[61]<<8) + 92) < (m - 1))
|
|
*ux = (buf[n] | (buf[n+1]<<8)) == 3;
|
|
else
|
|
*ux = 0;
|
|
}
|
|
}
|
|
else if (!ux)
|
|
r = -1;
|
|
else if (errno == ENOENT)
|
|
{
|
|
oerrno = errno;
|
|
r = -1;
|
|
}
|
|
else
|
|
{
|
|
r = 0;
|
|
*ux = 0;
|
|
}
|
|
errno = oerrno;
|
|
return r;
|
|
}
|
|
|
|
#if _win32_botch_access
|
|
|
|
extern int
|
|
access(const char* path, int op)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
char buf[PATH_MAX];
|
|
|
|
oerrno = errno;
|
|
if ((r = sysaccess(path, op)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
|
|
{
|
|
errno = oerrno;
|
|
r = sysaccess(buf, op);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_alarm
|
|
|
|
extern unsigned int
|
|
alarm(unsigned int s)
|
|
{
|
|
unsigned int n;
|
|
unsigned int r;
|
|
|
|
static unsigned int a;
|
|
|
|
n = (unsigned int)time(NiL);
|
|
if (a <= n)
|
|
r = 0;
|
|
else
|
|
r = a - n;
|
|
a = n + s - 1;
|
|
(void)sysalarm(s);
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_chmod
|
|
|
|
extern int
|
|
chmod(const char* path, mode_t mode)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
char buf[PATH_MAX];
|
|
|
|
if ((r = syschmod(path, mode)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
|
|
{
|
|
errno = oerrno;
|
|
return syschmod(buf, mode);
|
|
}
|
|
if (!(r = syschmod(path, mode)) &&
|
|
(mode & (S_IXUSR|S_IXGRP|S_IXOTH)) &&
|
|
!suffix(path) &&
|
|
(strlen(path) + 4) < sizeof(buf))
|
|
{
|
|
oerrno = errno;
|
|
if (!magic(path, NiL))
|
|
{
|
|
snprintf(buf, sizeof(buf), "%s.exe", path);
|
|
sysrename(path, buf);
|
|
}
|
|
errno = oerrno;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_execve || _lib_spawn_mode
|
|
|
|
#if _lib_spawn_mode
|
|
|
|
/*
|
|
* can anyone get const prototype args straight?
|
|
*/
|
|
|
|
#define execve ______execve
|
|
#define spawnve ______spawnve
|
|
|
|
#include <process.h>
|
|
|
|
#undef execve
|
|
#undef spawnve
|
|
|
|
#endif
|
|
|
|
#if CONVERT
|
|
|
|
/*
|
|
* this intercept converts dos env vars to unix
|
|
* we'd rather intercept main but can't twist cc to do it
|
|
* getuid() gets ksh to do the right thing and
|
|
* that's our main concern
|
|
*
|
|
* DOSPATHVARS='a b c' convert { a b c }
|
|
*/
|
|
|
|
static int convertinit;
|
|
|
|
/*
|
|
* convertvars[0] names the list of env var names
|
|
* convertvars[i] are not converted
|
|
*/
|
|
|
|
static const char* convertvars[] = { "DOSPATHVARS", "PATH" };
|
|
|
|
static int
|
|
convert(register const char* d, const char* s)
|
|
{
|
|
register const char* t;
|
|
register const char* v;
|
|
int i;
|
|
|
|
for (i = 0; i < elementsof(convertvars); i++)
|
|
{
|
|
for (v = convertvars[i], t = s; *t && *t == *v; t++, v++);
|
|
if (*t == '=' && *v == 0)
|
|
return 0;
|
|
}
|
|
for (;;)
|
|
{
|
|
while (*d == ' ' || *d == '\t')
|
|
d++;
|
|
if (!*d)
|
|
break;
|
|
for (t = s; *t && *t == *d; d++, t++);
|
|
if (*t == '=' && (*d == ' ' || *d == '\t' || *d == 0))
|
|
return t - s + 1;
|
|
while (*d && *d != ' ' && *d != '\t')
|
|
d++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uid_t
|
|
getuid(void)
|
|
{
|
|
register char* d;
|
|
register char* s;
|
|
register char* t;
|
|
register char** e;
|
|
int n;
|
|
int m;
|
|
|
|
if (!convertinit++ && (d = getenv(convertvars[0])))
|
|
for (e = environ; s = *e; e++)
|
|
if ((n = convert(d, s)) && (m = cygwin_win32_to_posix_path_list_buf_size(s + n)) > 0)
|
|
{
|
|
if (!(t = malloc(n + m + 1)))
|
|
break;
|
|
*e = t;
|
|
memcpy(t, s, n);
|
|
cygwin_win32_to_posix_path_list(s + n, t + n);
|
|
}
|
|
return sysgetuid();
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef _P_OVERLAY
|
|
#define _P_OVERLAY (-1)
|
|
#endif
|
|
|
|
#define DEBUG 1
|
|
|
|
static pid_t
|
|
runve(int mode, const char* path, char* const* argv, char* const* envv)
|
|
{
|
|
register char* s;
|
|
register char** p;
|
|
register char** v;
|
|
|
|
void* m1;
|
|
void* m2;
|
|
pid_t pid;
|
|
int oerrno;
|
|
int ux;
|
|
int n;
|
|
#if defined(_P_DETACH) && defined(_P_NOWAIT)
|
|
int pgrp;
|
|
#endif
|
|
#if CONVERT
|
|
char* d;
|
|
char* t;
|
|
int m;
|
|
#endif
|
|
struct stat st;
|
|
char buf[PATH_MAX];
|
|
char tmp[PATH_MAX];
|
|
|
|
#if DEBUG
|
|
static int trace;
|
|
#endif
|
|
|
|
#if defined(_P_DETACH) && defined(_P_NOWAIT)
|
|
if (mode == _P_DETACH)
|
|
{
|
|
/*
|
|
* 2004-02-29 cygwin _P_DETACH is useless:
|
|
* spawn*() returns 0 instead of the spawned pid
|
|
* spawned { pgid sid } are the same as the parent
|
|
*/
|
|
|
|
mode = _P_NOWAIT;
|
|
pgrp = 1;
|
|
}
|
|
else
|
|
pgrp = 0;
|
|
#endif
|
|
if (!envv)
|
|
envv = (char* const*)environ;
|
|
m1 = m2 = 0;
|
|
oerrno = errno;
|
|
#if DEBUG
|
|
if (!trace)
|
|
trace = (s = getenv("_AST_exec_trace")) ? *s : 'n';
|
|
#endif
|
|
if (execrate(path, buf, sizeof(buf), 0))
|
|
{
|
|
if (!sysstat(buf, &st))
|
|
path = (const char*)buf;
|
|
else
|
|
errno = oerrno;
|
|
}
|
|
if (path != (const char*)buf && sysstat(path, &st))
|
|
return -1;
|
|
if (!S_ISREG(st.st_mode) || !(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
|
|
{
|
|
errno = EACCES;
|
|
return -1;
|
|
}
|
|
if (magic(path, &ux))
|
|
{
|
|
#if _CYGWIN_fork_works
|
|
errno = ENOEXEC;
|
|
return -1;
|
|
#else
|
|
ux = 1;
|
|
p = (char**)argv;
|
|
while (*p++);
|
|
if (!(v = (char**)malloc((p - (char**)argv + 2) * sizeof(char*))))
|
|
{
|
|
errno = EAGAIN;
|
|
return -1;
|
|
}
|
|
m1 = v;
|
|
p = v;
|
|
*p++ = (char*)path;
|
|
*p++ = (char*)path;
|
|
path = (const char*)pathshell();
|
|
if (*argv)
|
|
argv++;
|
|
while (*p++ = (char*)*argv++);
|
|
argv = (char* const*)v;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* the win32 dll search order is
|
|
* (1) the directory of path
|
|
* (2) .
|
|
* (3) /c/(WINNT|WINDOWS)/system32 /c/(WINNT|WINDOWS)
|
|
* (4) the directories on $PATH
|
|
* there are no cygwin dlls in (3), so if (1) and (2) fail
|
|
* to produce the required dlls it's up to (4)
|
|
*
|
|
* the standard allows PATH to be anything once the path
|
|
* to an executable is determined; this code ensures that PATH
|
|
* contains /bin so that at least the cygwin dll, required
|
|
* by all cygwin executables, will be found
|
|
*/
|
|
|
|
if (p = (char**)envv)
|
|
{
|
|
n = 1;
|
|
while (s = *p++)
|
|
if (strneq(s, "PATH=", 5))
|
|
{
|
|
s += 5;
|
|
do
|
|
{
|
|
s = pathcat(s, ':', NiL, "", tmp, sizeof(tmp));
|
|
if (streq(tmp, "/usr/bin/") || streq(tmp, "/bin/"))
|
|
{
|
|
n = 0;
|
|
break;
|
|
}
|
|
} while (s);
|
|
if (n)
|
|
{
|
|
n = 0;
|
|
snprintf(tmp, sizeof(tmp), "%s:/bin", *(p - 1));
|
|
*(p - 1) = tmp;
|
|
}
|
|
break;
|
|
}
|
|
if (n)
|
|
{
|
|
n = p - (char**)envv + 1;
|
|
p = (char**)envv;
|
|
if (v = (char**)malloc(n * sizeof(char*)))
|
|
{
|
|
m2 = v;
|
|
envv = (char* const*)v;
|
|
*v++ = strcpy(tmp, "PATH=/bin");
|
|
while (*v++ = *p++);
|
|
}
|
|
}
|
|
#if CONVERT
|
|
if (!ux && (d = getenv(convertvars[0])))
|
|
for (p = (char**)envv; s = *p; p++)
|
|
if ((n = convert(d, s)) && (m = cygwin_posix_to_win32_path_list_buf_size(s + n)) > 0)
|
|
{
|
|
if (!(t = malloc(n + m + 1)))
|
|
break;
|
|
*p = t;
|
|
memcpy(t, s, n);
|
|
cygwin_posix_to_win32_path_list(s + n, t + n);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if DEBUG
|
|
if (trace == 'a' || trace == 'e')
|
|
{
|
|
sfprintf(sfstderr, "%s %s [", mode == _P_OVERLAY ? "_execve" : "_spawnve", path);
|
|
for (n = 0; argv[n]; n++)
|
|
sfprintf(sfstderr, " '%s'", argv[n]);
|
|
if (trace == 'e')
|
|
{
|
|
sfprintf(sfstderr, " ] [");
|
|
for (n = 0; envv[n]; n++)
|
|
sfprintf(sfstderr, " '%s'", envv[n]);
|
|
}
|
|
sfprintf(sfstderr, " ]\n");
|
|
sfsync(sfstderr);
|
|
}
|
|
#endif
|
|
#if _lib_spawn_mode
|
|
if (mode != _P_OVERLAY)
|
|
{
|
|
pid = sysspawnve(mode, path, argv, envv);
|
|
#if defined(_P_DETACH) && defined(_P_NOWAIT)
|
|
if (pid > 0 && pgrp)
|
|
setpgid(pid, 0);
|
|
#endif
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#if defined(_P_DETACH) && defined(_P_NOWAIT)
|
|
if (pgrp)
|
|
setpgid(0, 0);
|
|
#endif
|
|
pid = sysexecve(path, argv, envv);
|
|
}
|
|
if (m1)
|
|
free(m1);
|
|
if (m2)
|
|
free(m2);
|
|
return pid;
|
|
}
|
|
|
|
#if _win32_botch_execve
|
|
|
|
extern pid_t
|
|
execve(const char* path, char* const* argv, char* const* envv)
|
|
{
|
|
return runve(_P_OVERLAY, path, argv, envv);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _lib_spawn_mode
|
|
|
|
extern pid_t
|
|
spawnve(int mode, const char* path, char* const* argv, char* const* envv)
|
|
{
|
|
return runve(mode, path, argv, envv);
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_getpagesize
|
|
|
|
extern size_t
|
|
getpagesize(void)
|
|
{
|
|
return 64 * 1024;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_link
|
|
|
|
extern int
|
|
link(const char* fp, const char* tp)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
char fb[PATH_MAX];
|
|
char tb[PATH_MAX];
|
|
|
|
oerrno = errno;
|
|
if ((r = syslink(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1))
|
|
{
|
|
if (execrate(tp, tb, sizeof(tb), 1))
|
|
tp = tb;
|
|
errno = oerrno;
|
|
r = syslink(fb, tp);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_open || _win32_botch_copy
|
|
|
|
#if _win32_botch_copy
|
|
|
|
/*
|
|
* this should intercept the important cases
|
|
* dup*() and exec*() fd's will not be intercepted
|
|
*/
|
|
|
|
typedef struct Exe_test_s
|
|
{
|
|
int test;
|
|
ino_t ino;
|
|
char path[PATH_MAX];
|
|
} Exe_test_t;
|
|
|
|
static Exe_test_t* exe[16];
|
|
|
|
extern int
|
|
close(int fd)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
struct stat st;
|
|
char buf[PATH_MAX];
|
|
|
|
if (fd >= 0 && fd < elementsof(exe) && exe[fd])
|
|
{
|
|
r = exe[fd]->test;
|
|
exe[fd]->test = 0;
|
|
if (r > 0 && !fstat(fd, &st) && st.st_ino == exe[fd]->ino)
|
|
{
|
|
if (r = sysclose(fd))
|
|
return r;
|
|
oerrno = errno;
|
|
if (!stat(exe[fd]->path, &st) && st.st_ino == exe[fd]->ino)
|
|
{
|
|
snprintf(buf, sizeof(buf), "%s.exe", exe[fd]->path);
|
|
sysrename(exe[fd]->path, buf);
|
|
}
|
|
errno = oerrno;
|
|
return 0;
|
|
}
|
|
}
|
|
return sysclose(fd);
|
|
}
|
|
|
|
extern ssize_t
|
|
write(int fd, const void* buf, size_t n)
|
|
{
|
|
if (fd >= 0 && fd < elementsof(exe) && exe[fd] && exe[fd]->test < 0)
|
|
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);
|
|
return syswrite(fd, buf, n);
|
|
}
|
|
|
|
#endif
|
|
|
|
extern int
|
|
open(const char* path, int flags, ...)
|
|
{
|
|
int fd;
|
|
int mode;
|
|
int oerrno;
|
|
char buf[PATH_MAX];
|
|
#if _win32_botch_copy
|
|
struct stat st;
|
|
#endif
|
|
va_list ap;
|
|
|
|
va_start(ap, flags);
|
|
mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
|
|
oerrno = errno;
|
|
fd = sysopen(path, flags, mode);
|
|
#if _win32_botch_open
|
|
if (fd < 0 && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
|
|
{
|
|
errno = oerrno;
|
|
fd = sysopen(buf, flags, mode);
|
|
}
|
|
#endif
|
|
#if _win32_botch_copy
|
|
if (fd >= 0 && fd < elementsof(exe) && strlen(path) < PATH_MAX &&
|
|
(flags & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC) && (mode & 0111))
|
|
{
|
|
if (!suffix(path) && !fstat(fd, &st) && (exe[fd] || (exe[fd] = (Exe_test_t*)malloc(sizeof(Exe_test_t)))))
|
|
{
|
|
exe[fd]->test = -1;
|
|
exe[fd]->ino = st.st_ino;
|
|
strcpy(exe[fd]->path, path);
|
|
}
|
|
errno = oerrno;
|
|
}
|
|
#endif
|
|
va_end(ap);
|
|
return fd;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_pathconf
|
|
|
|
extern long
|
|
pathconf(const char* path, int op)
|
|
{
|
|
if (sysaccess(path, F_OK))
|
|
return -1;
|
|
return syspathconf(path, op);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_rename
|
|
|
|
extern int
|
|
rename(const char* fp, const char* tp)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
char fb[PATH_MAX];
|
|
char tb[PATH_MAX];
|
|
|
|
oerrno = errno;
|
|
if ((r = sysrename(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1))
|
|
{
|
|
if (execrate(tp, tb, sizeof(tb), 1))
|
|
tp = tb;
|
|
errno = oerrno;
|
|
r = sysrename(fb, tp);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_stat
|
|
|
|
extern int
|
|
stat(const char* path, struct stat* st)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
char buf[PATH_MAX];
|
|
|
|
oerrno = errno;
|
|
if ((r = sysstat(path, st)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
|
|
{
|
|
errno = oerrno;
|
|
r = sysstat(buf, st);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_truncate
|
|
|
|
extern int
|
|
truncate(const char* path, off_t offset)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
char buf[PATH_MAX];
|
|
|
|
oerrno = errno;
|
|
if ((r = systruncate(path, offset)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
|
|
{
|
|
errno = oerrno;
|
|
r = systruncate(buf, offset);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_unlink
|
|
|
|
extern int
|
|
unlink(const char* path)
|
|
{
|
|
int r;
|
|
int drive;
|
|
int mask;
|
|
int suffix;
|
|
int stop;
|
|
int oerrno;
|
|
unsigned long base;
|
|
char buf[PATH_MAX];
|
|
char tmp[MAX_PATH];
|
|
|
|
#define DELETED_DIR_1 7
|
|
#define DELETED_DIR_2 16
|
|
|
|
static char deleted[] = "%c:\\temp\\.deleted\\%08x.%03x";
|
|
|
|
static int count = 0;
|
|
|
|
#if __CYGWIN__
|
|
|
|
DWORD fattr = FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE;
|
|
DWORD share = FILE_SHARE_DELETE;
|
|
HANDLE hp;
|
|
struct stat st;
|
|
char nat[MAX_PATH];
|
|
|
|
oerrno = errno;
|
|
if (lstat(path, &st) || !S_ISREG(st.st_mode))
|
|
goto try_unlink;
|
|
cygwin_conv_to_full_win32_path(path, nat);
|
|
if (!strncasecmp(nat + 1, ":\\temp\\", 7))
|
|
goto try_unlink;
|
|
drive = nat[0];
|
|
path = (const char*)nat;
|
|
for (;;)
|
|
{
|
|
hp = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
|
if (hp != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hp);
|
|
errno = oerrno;
|
|
return 0;
|
|
}
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
|
break;
|
|
if (path == (const char*)buf || !execrate(path, buf, sizeof(buf), 1))
|
|
{
|
|
errno = ENOENT;
|
|
return -1;
|
|
}
|
|
path = (const char*)buf;
|
|
}
|
|
#else
|
|
if (sysaccess(path, 0))
|
|
#if _win32_botch_access
|
|
{
|
|
if (errno != ENOENT || !execrate(path, buf, sizeof(buf), 1) || sysaccess(buf, 0))
|
|
return -1;
|
|
path = (const char*)buf;
|
|
}
|
|
#else
|
|
return -1;
|
|
#endif
|
|
drive = 'C':
|
|
#endif
|
|
|
|
/*
|
|
* rename to a `deleted' path just in case the file is open
|
|
* otherwise directory readers may choke on phantom entries
|
|
*/
|
|
|
|
base = ((getuid() & 0xffff) << 16) | (time(NiL) & 0xffff);
|
|
suffix = (getpid() & 0xfff) + count++;
|
|
snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix);
|
|
if (!sysrename(path, tmp))
|
|
{
|
|
path = (const char*)tmp;
|
|
goto try_delete;
|
|
}
|
|
if (errno != ENOTDIR && errno != ENOENT)
|
|
goto try_unlink;
|
|
tmp[DELETED_DIR_2] = 0;
|
|
if (sysaccess(tmp, 0))
|
|
{
|
|
mask = umask(0);
|
|
tmp[DELETED_DIR_1] = 0;
|
|
if (sysaccess(tmp, 0) && mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO))
|
|
{
|
|
umask(mask);
|
|
goto try_unlink;
|
|
}
|
|
tmp[DELETED_DIR_1] = '\\';
|
|
r = mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO);
|
|
umask(mask);
|
|
if (r)
|
|
goto try_unlink;
|
|
errno = 0;
|
|
}
|
|
tmp[DELETED_DIR_2] = '\\';
|
|
if (!errno && !sysrename(path, tmp))
|
|
{
|
|
path = (const char*)tmp;
|
|
goto try_delete;
|
|
}
|
|
#if !__CYGWIN__
|
|
if (errno == ENOENT)
|
|
{
|
|
#if !_win32_botch_access
|
|
if (execrate(path, buf, sizeof(buf), 1) && !sysrename(buf, tmp))
|
|
path = (const char*)tmp;
|
|
#endif
|
|
goto try_unlink;
|
|
}
|
|
#endif
|
|
stop = suffix;
|
|
do
|
|
{
|
|
snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix);
|
|
if (!sysrename(path, tmp))
|
|
{
|
|
path = (const char*)tmp;
|
|
goto try_delete;
|
|
}
|
|
if (++suffix > 0xfff)
|
|
suffix = 0;
|
|
} while (suffix != stop);
|
|
try_delete:
|
|
#if __CYGWIN__
|
|
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);
|
|
if (hp != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hp);
|
|
errno = oerrno;
|
|
return 0;
|
|
}
|
|
#endif
|
|
try_unlink:
|
|
errno = oerrno;
|
|
return sysunlink(path);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _win32_botch_utime
|
|
|
|
#if __CYGWIN__
|
|
|
|
/*
|
|
* cygwin refuses to set st_ctime for some operations
|
|
* this rejects that refusal
|
|
*/
|
|
|
|
static void
|
|
ctime_now(const char* path)
|
|
{
|
|
HANDLE hp;
|
|
SYSTEMTIME st;
|
|
FILETIME ct;
|
|
WIN32_FIND_DATA ff;
|
|
struct stat fs;
|
|
int oerrno;
|
|
char tmp[MAX_PATH];
|
|
|
|
if (sysstat(path, &fs) || (fs.st_mode & S_IWUSR) || syschmod(path, (fs.st_mode | S_IWUSR) & S_IPERM))
|
|
fs.st_mode = 0;
|
|
cygwin_conv_to_win32_path(path, tmp);
|
|
hp = CreateFile(tmp, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hp && hp != INVALID_HANDLE_VALUE)
|
|
{
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &ct);
|
|
SetFileTime(hp, &ct, 0, 0);
|
|
CloseHandle(hp);
|
|
}
|
|
if (fs.st_mode)
|
|
syschmod(path, fs.st_mode & S_IPERM);
|
|
errno = oerrno;
|
|
}
|
|
|
|
#else
|
|
|
|
#define ctime_now(p)
|
|
|
|
#endif
|
|
|
|
extern int
|
|
utimes(const char* path, const struct timeval* ut)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
char buf[PATH_MAX];
|
|
|
|
oerrno = errno;
|
|
if ((r = sysutimes(path, ut)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
|
|
{
|
|
errno = oerrno;
|
|
r = sysutimes(path = buf, ut);
|
|
}
|
|
if (!r)
|
|
ctime_now(path);
|
|
return r;
|
|
}
|
|
|
|
extern int
|
|
utime(const char* path, const struct utimbuf* ut)
|
|
{
|
|
int r;
|
|
int oerrno;
|
|
char buf[PATH_MAX];
|
|
|
|
oerrno = errno;
|
|
if ((r = sysutime(path, ut)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
|
|
{
|
|
errno = oerrno;
|
|
r = sysutime(path = buf, ut);
|
|
}
|
|
if (!r)
|
|
ctime_now(path);
|
|
return r;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/*
|
|
* some systems (sun) miss a few functions required by their
|
|
* own bsd-like macros
|
|
*/
|
|
|
|
#if !_lib_bzero || defined(bzero)
|
|
|
|
#undef bzero
|
|
|
|
void
|
|
bzero(void* b, size_t n)
|
|
{
|
|
memset(b, 0, n);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if !_lib_getpagesize || defined(getpagesize)
|
|
|
|
#ifndef OMITTED
|
|
#define OMITTED 1
|
|
#endif
|
|
|
|
#undef getpagesize
|
|
|
|
#ifdef _SC_PAGESIZE
|
|
#undef _AST_PAGESIZE
|
|
#define _AST_PAGESIZE (int)sysconf(_SC_PAGESIZE)
|
|
#else
|
|
#ifndef _AST_PAGESIZE
|
|
#define _AST_PAGESIZE 4096
|
|
#endif
|
|
#endif
|
|
|
|
int
|
|
getpagesize()
|
|
{
|
|
return _AST_PAGESIZE;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if __CYGWIN__ && defined(__IMPORT__) && defined(__EXPORT__)
|
|
|
|
#ifndef OMITTED
|
|
#define OMITTED 1
|
|
#endif
|
|
|
|
/*
|
|
* a few _imp__FUNCTION symbols are needed to avoid
|
|
* static link multiple definitions
|
|
*/
|
|
|
|
#ifndef strtod
|
|
__EXPORT__ double (*_imp__strtod)(const char*, char**) = strtod;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/* Kludge to deal with GCC's overzealous optimizer breaking the pow functions.
|
|
*
|
|
* Removal of this will break IEEE floating point on the SVR4 platforms.
|
|
*/
|
|
#if _need_ast_pow_funs
|
|
# if _lib_powf
|
|
float (*volatile _ast_ppowf)(float,float) = &powf;
|
|
float _ast_powf(float x, float y)
|
|
{
|
|
return x == 1.0F ? 1.0F : (*_ast_ppowf)(x,y);
|
|
}
|
|
# endif
|
|
|
|
# if _lib_pow
|
|
double (*volatile _ast_ppow)(double,double) = &pow;
|
|
double _ast_pow(double x, double y)
|
|
{
|
|
return x == 1.0 ? 1.0 : (*_ast_ppow)(x,y);
|
|
}
|
|
# endif
|
|
|
|
# if _lib_powl
|
|
long double (*volatile _ast_ppowl)(long double,long double) = &powl;
|
|
long double _ast_powl(long double x, long double y)
|
|
{
|
|
return x == 1.0L ? 1.0L : (*_ast_ppowl)(x,y);
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
#ifndef OMITTED
|
|
|
|
NoN(omitted)
|
|
|
|
#endif
|