/****************************************************************************/ /* */ /* Onions Network Streams Library */ /* */ /* O S - D E P E N D */ /* */ /* C B o d y */ /* */ /* Copyright (C) 1997 Regents of the University of California */ /* */ /* Onions is free software; you can redistribute it and/or modify it under */ /* the terms of the GNU General Public License as published by the Free */ /* Software Foundation, with or without the single exception listed below; */ /* either version 2, or (at your option) any later version. Onions is */ /* distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;*/ /* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A */ /* PARTICULAR PURPOSE. See the GNU General Public License for more details.*/ /* You should have received a copy of the GNU General Public License */ /* distributed with Onions; see the file COPYING. If not, write to the */ /* Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA */ /* 02111-1307, USA. */ /* */ /* As a special exception, if other files instantiate generics from this */ /* library, or you link this library with other files to produce an */ /* executable, this library does not by itself cause the resulting */ /* executable to be covered by the GNU General Public License. This */ /* exception does not however invalidate any other reasons why the */ /* executable file might be covered by the GNU General Public License. */ /* */ /* Created in 1997 by Roy T. Fielding */ /****************************************************************************/ /* */ /* This file contains an operating system-independent interface to those */ /* C system library routines and data structures that are often system- */ /* dependent. Since Ada95 has no equivalent to the standard include files */ /* of C, we can't rely on a simple Import to match the C data structure */ /* with our Ada95 equivalent. We thus produce system-independent data */ /* structures here that can be matched (and imported) via onions-os.ads. */ /* */ #include "config.h" #define _REENTRANT #include #include #include #include #include #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if defined(HAVE_POLL) && defined(HAVE_POLL_H) # include # include #endif #include "os-depend.h" /* The thread-safe errno is defined as a macro on Solaris (and probably all * POSIX systems, though I haven't checked others) which makes it a pain * to access via Ada95. */ int onions_get_errno (void) { return errno; } void onions_set_errno (int new_errno) { errno = new_errno; } /* The data structure used by the various stat functions is extremely * OS-dependent, requiring a general conversion to our own special stat * structure containing only the common fields, converted to long form. */ static void convert_stats (struct stat *statbuf, onions_statrec *buf) { buf->file_mode = (unsigned long) statbuf->st_mode; buf->file_ino = (unsigned long) statbuf->st_ino; buf->file_dev = (unsigned long) statbuf->st_dev; buf->file_nlink = (unsigned long) statbuf->st_nlink; buf->file_uid = (long) statbuf->st_uid; buf->file_gid = (long) statbuf->st_gid; buf->file_size = (long) statbuf->st_size; buf->file_atime = (long) statbuf->st_atime; buf->file_mtime = (long) statbuf->st_mtime; buf->file_ctime = (long) statbuf->st_ctime; } int onions_stat (const char *path, onions_statrec *buf) { int rv; struct stat statbuf; do { rv = stat(path, &statbuf); } while (rv == -1 && errno == EINTR); convert_stats(&statbuf, buf); return rv; } int onions_lstat (const char *path, onions_statrec *buf) { int rv; struct stat statbuf; do { rv = lstat(path, &statbuf); } while (rv == -1 && errno == EINTR); convert_stats(&statbuf, buf); return rv; } int onions_fstat (int fd, onions_statrec *buf) { int rv; struct stat statbuf; do { rv = fstat(fd, &statbuf); } while (rv == -1 && errno == EINTR); convert_stats(&statbuf, buf); return rv; } /* Using poll or select (less efficient but more portable), wait up to * a given number of milliseconds (0 => forever) for the given file descriptor * to become readable (state == 1), writeable (state == 2), either one, * or a fatal error event occurs. Returns * -1 indicating an error, or * 0 indicating the timeout occurred, or * >0 indicating our descriptor is ready. */ int onions_wait_for_fd (int state, int fd, long millisecs) { int rv; #if defined(HAVE_POLL) && defined(HAVE_POLL_H) struct pollfd fdarray[1]; int timeout; if (millisecs <= 0) timeout = INFTIM; else timeout = (int) millisecs; fdarray[0].fd = fd; if (state == 1) fdarray[0].events = POLLIN; else if (state == 2) fdarray[0].events = POLLOUT; else fdarray[0].events = POLLIN | POLLOUT; do { rv = poll(fdarray, 1, timeout); } while (rv == -1 && errno == EINTR); #else struct timeval tv, *tvp; fd_set fdset; long save_sec, save_usec; FD_ZERO(&fdset); if (millisecs > 0) { save_sec = millisecs / 1000; save_usec = (millisecs % 1000) * 1000; tvp = &tv; } else { save_usec = save_sec = 0; tvp = NULL; } do { /* The select parameters must be reset on each pass */ FD_SET(fd, &fdset); tv.tv_sec = save_sec; tv.tv_usec = save_usec; if (state == 1) rv = select(fd + 1, &fdset, NULL, NULL, tvp); else if (state == 2) rv = select(fd + 1, NULL, &fdset, NULL, tvp); else rv = select(fd + 1, &fdset, &fdset, NULL, tvp); } while (rv == -1 && errno == EINTR); #endif return rv; } /* Read the already open directory pointed to by dirp and place the * next filename in the provided buffer of max length buflen. * NOTE: buflen should be at least NAME_MAX + 1. * Returns -1 on error (see errno), 0 on end-of-dir, or the length * of the filename placed in buf. */ ssize_t onions_readdir (DIR *dirp, void *buf, const size_t buflen) { #ifdef HAVE_READDIR_R char entry[sizeof(struct dirent) + NAME_MAX + 1]; #else struct dirent entry; #endif struct dirent *ep; size_t flen; errno = 0; #ifdef HAVE_READDIR_R /* * The reentrant version of readdir is called readdir_r. * Unfortunately, the regular Solaris readdir_r and the final POSIX * readdir_r have different signatures. This code uses the default * Solaris version, since I can't reliably test the POSIX one. * If you get compiler errors here, it should be easy to replace * the line below with one that works on your system. If all else * fails, just undef HAVE_READDIR_R and use the non-threadsafe readdir. */ while ((ep = readdir_r(dirp, (struct dirent *)&entry)) != NULL) { #else while ((ep = readdir(dirp)) != NULL) { #endif if ((ep->d_name[0] == '.') && ((ep->d_name[1] == '\0') || ((ep->d_name[1] == '.') && (ep->d_name[2] == '\0')))) continue; /* ignore the "." and ".." entries (if any) */ flen = NAMLEN(ep); if (flen > buflen) flen = buflen; /* truncate filenames that are too long */ memcpy(buf, ep->d_name, flen); return flen; } return (errno == 0 ? 0 : -1); }