1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/src/lib/libast/comp/omitted.c
Lev Kujawski 72968eaed6
Revise the pow(1,inf) IEEE feature test to defeat clever compilers (#184)
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.
2021-02-18 18:45:27 +00:00

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