Hopscotch table improvements
[sbcl.git] / src / runtime / wrap.c
blob5747033351f930aa85e8dd34d99c31174300dbbf
1 /*
2 * wrappers around low-level operations to provide a simpler interface
3 * to the operations that Lisp (and some contributed modules) needs.
5 * The functions in this file are typically called directly from Lisp.
6 * Thus, when their signature changes, they don't need updates in a .h
7 * file somewhere, but they do need updates in the Lisp code. FIXME:
8 * It would be nice to enforce this at compile time. It mighn't even
9 * be all that hard: make the cross-compiler versions of DEFINE-ALIEN-FOO
10 * macros accumulate strings in a list which then gets written out at
11 * the end of sbcl2.h at the end of cross-compilation, then rerun
12 * 'make' in src/runtime/ using the new sbcl2.h as sbcl.h (and make
13 * sure that all the files in src/runtime/ include sbcl.h). */
16 * This software is part of the SBCL system. See the README file for
17 * more information.
19 * This software is derived from the CMU CL system, which was
20 * written at Carnegie Mellon University and released into the
21 * public domain. The software is in the public domain and is
22 * provided with absolutely no warranty. See the COPYING and CREDITS
23 * files for more information.
26 #include "sbcl.h"
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <sys/stat.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <fcntl.h>
38 #include <math.h>
40 #ifndef LISP_FEATURE_WIN32
41 #include <pwd.h>
42 #include <time.h>
43 #include <sys/time.h>
44 #include <sys/wait.h>
45 #include <sys/resource.h>
46 #include <netdb.h>
47 #endif
48 #include <stdio.h>
50 #if defined(LISP_FEATURE_WIN32)
51 #define WIN32_LEAN_AND_MEAN
52 #include <errno.h>
53 #include <math.h>
54 #endif
56 #include "runtime.h"
57 #include "wrap.h"
59 /* Although it might seem as though this should be in some standard
60 Unix header, according to Perry E. Metzger, in a message on
61 sbcl-devel dated 2004-03-29, this is the POSIXly-correct way of
62 using environ: by an explicit declaration. -- CSR, 2004-03-30 */
63 extern char **environ;
66 * stuff needed by CL:DIRECTORY and other Lisp directory operations
71 * readlink(2) stuff
74 #ifndef LISP_FEATURE_WIN32
75 /* a wrapped version of readlink(2):
76 * -- If path isn't a symlink, or is a broken symlink, return 0.
77 * -- If path is a symlink, return a newly allocated string holding
78 * the thing it's linked to. */
79 char *
80 wrapped_readlink(char *path)
82 int bufsiz = strlen(path) + 16;
83 while (1) {
84 char *result = malloc(bufsiz);
85 int n_read = readlink(path, result, bufsiz);
86 if (n_read < 0) {
87 free(result);
88 return 0;
89 } else if (n_read < bufsiz) {
90 result[n_read] = 0;
91 return result;
92 } else {
93 free(result);
94 bufsiz *= 2;
98 #endif
101 * realpath(3), including a wrapper for Windows.
103 char * sb_realpath (char *path)
105 #ifndef LISP_FEATURE_WIN32
106 char *ret;
107 int errnum;
109 if ((ret = calloc(PATH_MAX, sizeof(char))) == NULL)
110 return NULL;
111 if (realpath(path, ret) == NULL) {
112 errnum = errno;
113 free(ret);
114 errno = errnum;
115 return NULL;
117 return(ret);
118 #else
119 char *ret;
120 char *cp;
121 int errnum;
123 if ((ret = calloc(MAX_PATH, sizeof(char))) == NULL)
124 return NULL;
125 if (GetFullPathName(path, MAX_PATH, ret, &cp) == 0) {
126 errnum = errno;
127 free(ret);
128 errno = errnum;
129 return NULL;
131 return(ret);
132 #endif
135 /* readdir, closedir, and dirent name accessor. The first three are not strictly
136 * necessary, but should save us some #!+netbsd in the build, and this also allows
137 * building Windows versions using the non-ANSI variants of FindFirstFile &co
138 * under the same API. (Use a structure that appends the handle to the WIN32_FIND_DATA
139 * as the return value from sb_opendir, on sb_readdir grab the name from the previous
140 * call and save the new one.) Nikodemus thought he would have to do that to support
141 * DIRECTORY on UNC paths, but turns out opendir &co do TRT on Windows already -- so
142 * leaving that bit of tedium for a later date, once we figure out the whole *A vs. *W
143 * issue out properly. ...FIXME, obviously, as per above.
145 * Once that is done, the lisp side functions are best named OS-OPENDIR, etc.
147 extern DIR *
148 sb_opendir(char * name)
150 return opendir(name);
153 extern struct dirent *
154 sb_readdir(DIR * dirp)
156 /* NULL returned from readdir() means it reached the end, NULL and
157 non-zero errno means an error occured.
158 When no error has occured, errno is not changed.
159 Set it to 0 beforehand. */
160 errno = 0;
161 return readdir(dirp);
164 extern int
165 sb_closedir(DIR * dirp)
167 return closedir(dirp);
170 extern char *
171 sb_dirent_name(struct dirent * ent)
173 return ent->d_name;
177 * stat(2) stuff
180 static void
181 copy_to_stat_wrapper(struct stat_wrapper *to, struct stat *from)
183 #define FROB(stem) to->wrapped_st_##stem = from->st_##stem
184 #ifndef LISP_FEATURE_WIN32
185 #define FROB2(stem) to->wrapped_st_##stem = from->st_##stem
186 #else
187 #define FROB2(stem) to->wrapped_st_##stem = 0;
188 #endif
189 FROB(dev);
190 FROB2(ino);
191 FROB(mode);
192 FROB(nlink);
193 FROB2(uid);
194 FROB2(gid);
195 FROB(rdev);
196 FROB(size);
197 FROB2(blksize);
198 FROB2(blocks);
199 FROB(atime);
200 FROB(mtime);
201 FROB(ctime);
202 #undef FROB
206 stat_wrapper(const char *file_name, struct stat_wrapper *buf)
208 struct stat real_buf;
209 int ret;
211 #ifdef LISP_FEATURE_WIN32
213 * Windows won't match the last component of a pathname if there
214 * is a trailing #\/ or #\\, except if it's <drive>:\ or <drive>:/
215 * in which case it behaves the other way around. So we remove the
216 * trailing directory separator unless we are being passed just a
217 * drive name (e.g. "c:\\"). Some, but not all, of this
218 * strangeness is documented at Microsoft's support site (as of
219 * 2006-01-08, at
220 * <http://support.microsoft.com/default.aspx?scid=kb;en-us;168439>)
222 char file_buf[MAX_PATH];
223 strcpy(file_buf, file_name);
224 int len = strlen(file_name);
225 if (len != 0 && (file_name[len-1] == '/' || file_name[len-1] == '\\') &&
226 !(len == 3 && file_name[1] == ':' && isalpha(file_name[0])))
227 file_buf[len-1] = '\0';
228 file_name = file_buf;
229 #endif
231 if ((ret = stat(file_name,&real_buf)) >= 0)
232 copy_to_stat_wrapper(buf, &real_buf);
233 return ret;
236 #ifndef LISP_FEATURE_WIN32
238 lstat_wrapper(const char *file_name, struct stat_wrapper *buf)
240 struct stat real_buf;
241 int ret;
242 if ((ret = lstat(file_name,&real_buf)) >= 0)
243 copy_to_stat_wrapper(buf, &real_buf);
244 return ret;
246 #else
247 /* cleaner to do it here than in Lisp */
248 int lstat_wrapper(const char *file_name, struct stat_wrapper *buf)
250 return stat_wrapper(file_name, buf);
252 #endif
255 fstat_wrapper(int filedes, struct stat_wrapper *buf)
257 struct stat real_buf;
258 int ret;
259 if ((ret = fstat(filedes,&real_buf)) >= 0)
260 copy_to_stat_wrapper(buf, &real_buf);
261 return ret;
264 /* A wrapper for mkstemp(3), for two reasons: (1) mkstemp does not
265 exist on Windows; (2) by passing down a mode_t, we don't need a
266 binding to chmod in SB-UNIX, and need not concern ourselves with
267 umask issues if we want to use mkstemp to make new files in
268 OPEN as implied by the cagey remark (in 'unix.lisp') that
269 "There are good reasons to implement some OPEN options with a[n]
270 mkstemp(3)-like routine, but we don't do that yet." */
272 int sb_mkstemp (char *template, mode_t mode) {
273 int fd;
274 #ifdef LISP_FEATURE_WIN32
275 #define PATHNAME_BUFFER_SIZE MAX_PATH
276 char buf[PATHNAME_BUFFER_SIZE];
278 while (1) {
279 /* Fruit fallen from the tree: for people who like
280 microoptimizations, we might not need to copy the whole
281 template on every loop, but only the last several characters.
282 But I didn't feel like testing the boundary cases in Windows's
283 _mktemp. */
284 strncpy(buf, template, PATHNAME_BUFFER_SIZE);
285 buf[PATHNAME_BUFFER_SIZE-1]=0; /* force NULL-termination */
286 if (_mktemp(buf)) {
287 if ((fd=open(buf, O_CREAT|O_EXCL|O_RDWR, mode))!=-1) {
288 strcpy(template, buf);
289 return (fd);
290 } else
291 if (errno != EEXIST)
292 return (-1);
293 } else
294 return (-1);
296 #undef PATHNAME_BUFFER_SIZE
297 #else
298 /* It makes no sense to reimplement mkstemp() with logic susceptible
299 to the exploit that mkstemp() was designed to avoid.
300 Unfortunately, there is a subtle bug in this more nearly correct technique.
301 open() uses the given creation mode ANDed with the process umask,
302 but fchmod() uses exactly the specified mode. Attempting to perform the
303 masking operation manually would result in another race: you can't obtain
304 the current mask except by calling umask(), which both sets and gets it.
305 But since RUN-PROGRAM is the only use of this, and the mode given is #o600
306 which is the default for mkstemp(), RUN-PROGRAM should be indifferent.
307 [The GNU C library documents but doesn't implement getumask() by the way.]
308 So we're patching a security hole with a known innocuous design flaw
309 by necessity to avoid the gcc linker warning that
310 "the use of `mktemp' is dangerous, better use `mkstemp'" */
311 fd = mkstemp(template);
312 if (fd != -1 && fchmod(fd, mode) == -1) {
313 close(fd); // got a file descriptor but couldn't fchmod() it
314 return -1;
316 return fd;
317 #endif
322 * getpwuid() stuff
325 #ifndef LISP_FEATURE_WIN32
326 /* Return a newly-allocated string holding the username for "uid", or
327 * NULL if there's no such user.
329 * KLUDGE: We also return NULL if malloc() runs out of memory
330 * (returning strdup() result) since it's not clear how to handle that
331 * error better. -- WHN 2001-12-28 */
332 char *
333 uid_username(int uid)
335 struct passwd *p = getpwuid(uid);
336 if (p) {
337 /* The object *p is a static struct which'll be overwritten by
338 * the next call to getpwuid(), so it'd be unsafe to return
339 * p->pw_name without copying. */
340 return strdup(p->pw_name);
341 } else {
342 return 0;
346 char *
347 passwd_homedir(struct passwd *p)
349 if (p) {
350 /* Let's be careful about this, shall we? */
351 size_t len = strlen(p->pw_dir);
352 if (p->pw_dir[len-1] == '/') {
353 return strdup(p->pw_dir);
354 } else {
355 char *result = malloc(len + 2);
356 if (result) {
357 unsigned int nchars = sprintf(result,"%s/",p->pw_dir);
358 if (nchars == len + 1) {
359 return result;
360 } else {
361 return 0;
363 } else {
364 return 0;
367 } else {
368 return 0;
372 char *
373 user_homedir(char *name)
375 return passwd_homedir(getpwnam(name));
378 char *
379 uid_homedir(uid_t uid)
381 return passwd_homedir(getpwuid(uid));
383 #endif /* !LISP_FEATURE_WIN32 */
386 * functions to get miscellaneous C-level variables
388 * (Doing this by calling functions lets us borrow the smarts of the C
389 * linker, so that things don't blow up when libc versions and thus
390 * variable locations change between compile time and run time.)
393 char **
394 wrapped_environ()
396 return environ;
399 #ifdef LISP_FEATURE_WIN32
400 #include <windows.h>
401 #include <time.h>
403 * faked-up implementation of select(). Right now just enough to get through
404 * second genesis.
406 int sb_select(int top_fd, DWORD *read_set, DWORD *write_set, DWORD *except_set, time_t *timeout)
409 * FIXME: Going forward, we may want to use MsgWaitForMultipleObjects
410 * in order to support a windows message loop inside serve-event.
412 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
413 int fds[MAXIMUM_WAIT_OBJECTS];
414 int num_handles;
415 int i;
416 DWORD retval;
417 int polling_write;
418 DWORD win_timeout;
420 num_handles = 0;
421 polling_write = 0;
422 for (i = 0; i < top_fd; i++) {
423 if (except_set) except_set[i >> 5] = 0;
424 if (write_set && (write_set[i >> 5] & (1 << (i & 31)))) polling_write = 1;
425 if (read_set[i >> 5] & (1 << (i & 31))) {
426 read_set[i >> 5] &= ~(1 << (i & 31));
427 fds[num_handles] = i;
428 handles[num_handles++] = (HANDLE) _get_osfhandle(i);
432 win_timeout = INFINITE;
433 if (timeout) win_timeout = (timeout[0] * 1000) + timeout[1];
435 /* Last parameter here is timeout in milliseconds. */
436 /* retval = WaitForMultipleObjects(num_handles, handles, 0, INFINITE); */
437 retval = WaitForMultipleObjects(num_handles, handles, 0, win_timeout);
439 if (retval < WAIT_ABANDONED) {
440 /* retval, at this point, is the index of the single live HANDLE/fd. */
441 read_set[fds[retval] >> 5] |= (1 << (fds[retval] & 31));
442 return 1;
444 return polling_write;
448 * Windows doesn't have gettimeofday(), and we need it for the compiler,
449 * for serve-event, and for a couple other things. We don't need a timezone
450 * yet, however, and the closest we can easily get to a timeval is the
451 * seconds part. So that's what we do.
453 #define UNIX_EPOCH_FILETIME 116444736000000000ULL
455 int sb_gettimeofday(long *timeval, long *timezone)
457 FILETIME ft;
458 ULARGE_INTEGER uft;
459 GetSystemTimeAsFileTime(&ft);
460 uft.LowPart = ft.dwLowDateTime;
461 uft.HighPart = ft.dwHighDateTime;
462 uft.QuadPart -= UNIX_EPOCH_FILETIME;
463 timeval[0] = uft.QuadPart / 10000000;
464 timeval[1] = (uft.QuadPart % 10000000)/10;
466 return 0;
468 #endif
471 /* We will need to define these things or their equivalents for Win32
472 eventually, but for now let's get it working for everyone else. */
473 #ifndef LISP_FEATURE_WIN32
474 /* From SB-BSD-SOCKETS, to get h_errno */
475 int get_h_errno()
477 return h_errno;
480 /* From SB-POSIX, wait-macros */
481 int wifexited(int status) {
482 return WIFEXITED(status);
484 int wexitstatus(int status) {
485 return WEXITSTATUS(status);
487 int wifsignaled(int status) {
488 return WIFSIGNALED(status);
490 int wtermsig(int status) {
491 return WTERMSIG(status);
493 int wifstopped(int status) {
494 return WIFSTOPPED(status);
496 int wstopsig(int status) {
497 return WSTOPSIG(status);
499 /* FIXME: POSIX also defines WIFCONTINUED, but that appears not to
500 exist on at least Linux... */
501 #endif /* !LISP_FEATURE_WIN32 */
503 /* From SB-POSIX, stat-macros */
504 int s_isreg(mode_t mode)
506 return S_ISREG(mode);
508 int s_isdir(mode_t mode)
510 return S_ISDIR(mode);
512 int s_ischr(mode_t mode)
514 return S_ISCHR(mode);
516 int s_isblk(mode_t mode)
518 return S_ISBLK(mode);
520 int s_isfifo(mode_t mode)
522 return S_ISFIFO(mode);
524 #ifndef LISP_FEATURE_WIN32
525 int s_islnk(mode_t mode)
527 #ifdef S_ISLNK
528 return S_ISLNK(mode);
529 #else
530 return ((mode & S_IFMT) == S_IFLNK);
531 #endif
533 int s_issock(mode_t mode)
535 #ifdef S_ISSOCK
536 return S_ISSOCK(mode);
537 #else
538 return ((mode & S_IFMT) == S_IFSOCK);
539 #endif
541 #endif /* !LISP_FEATURE_WIN32 */
543 #ifndef LISP_FEATURE_WIN32
544 int sb_getrusage(int who, struct rusage *rusage)
546 return getrusage(who, rusage);
549 int sb_gettimeofday(struct timeval *tp, void *tzp)
551 return gettimeofday(tp, tzp);
554 #ifndef LISP_FEATURE_DARWIN /* reimplements nanosleep in darwin-os.c */
555 void sb_nanosleep(time_t sec, int nsec)
557 struct timespec rqtp = {sec, nsec};
558 struct timespec rmtp;
560 while(nanosleep(&rqtp, &rmtp) && errno == EINTR) {
561 rqtp = rmtp;
562 /* The old lisp version stated
563 ;; KLUDGE: On Darwin, if an interrupt cases nanosleep to
564 ;; take longer than the requested time, the call will
565 ;; return with EINT and (unsigned)-1 seconds in the
566 ;; remainder timespec, which would cause us to enter
567 ;; nanosleep again for ~136 years. So, we check that the
568 ;; remainder time is actually decreasing.
570 ;; It would be neat to do this bit of defensive
571 ;; programming on all platforms, but unfortunately on
572 ;; Linux, REM can be a little higher than REQ if the
573 ;; nanosleep() call is interrupted quickly enough,
574 ;; probably due to the request being rounded up to the
575 ;; nearest HZ. This would cause the sleep to return way
576 ;; too early.
577 #!+darwin
578 (let ((rem-sec (slot rem 'tv-sec))
579 (rem-nsec (slot rem 'tv-nsec)))
580 (when (or (> secs rem-sec)
581 (and (= secs rem-sec) (>= nsecs rem-nsec)))
582 ;; Update for next round.
583 (setf secs rem-sec
584 nsecs rem-nsec)
587 but the Darwin variant is implemented elsewhere
591 #else
592 /* nanosleep() is not re-entrant on some versions of Darwin and is
593 * reimplemented it using the underlying syscalls.
595 int sb_nanosleep(time_t sec, int nsec);
596 #endif
598 void sb_nanosleep_double(double seconds) {
599 /* Some (which?) platforms, apparently, can't sleep more than 100
600 million seconds */
601 for (; seconds > 0; seconds -= 100000000.0) {
602 long sec = truncl(seconds);
603 long nsec = truncl((seconds - (double) sec) * 1e9);
604 sb_nanosleep(sec, nsec);
608 void sb_nanosleep_float(float seconds) {
609 sb_nanosleep_double(seconds);
612 int sb_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
613 struct timeval *timeout)
615 return select(nfds, readfds, writefds, exceptfds, timeout);
618 int sb_getitimer(int which, struct itimerval *value)
620 return getitimer(which, value);
623 int sb_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
625 return setitimer(which, value, ovalue);
628 int sb_utimes(char *path, struct timeval times[2])
630 return utimes(path, times);
632 #else /* !LISP_FEATURE_WIN32 */
633 #define SB_TRIG_WRAPPER(name) \
634 double sb_##name (double x) { \
635 return name(x); \
637 SB_TRIG_WRAPPER(acos)
638 SB_TRIG_WRAPPER(asin)
639 SB_TRIG_WRAPPER(cosh)
640 SB_TRIG_WRAPPER(sinh)
641 SB_TRIG_WRAPPER(tanh)
642 SB_TRIG_WRAPPER(asinh)
643 SB_TRIG_WRAPPER(acosh)
644 SB_TRIG_WRAPPER(atanh)
646 double sb_hypot (double x, double y) {
647 return hypot(x, y);
650 #endif