/*
   Unix SMB/Netbios implementation.
   Version 1.9.
   Samba system utilities

   Copyright (C) Andrew Tridgell 1992-1998

   Copyright (C) 2011-2017
   Free Software Foundation, Inc.

   This file is part of the Midnight Commander.

   The Midnight Commander 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, either version 3 of the License,
   or (at your option) any later version.

   The Midnight Commander 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
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "includes.h"

extern int DEBUGLEVEL;

/*
   The idea is that this file will eventually have wrappers around all
   important system calls in samba. The aims are:

   - to enable easier porting by putting OS dependent stuff in here

   - to allow for hooks into other "pseudo-filesystems"

   - to allow easier integration of things like the japanese extensions

   - to support the philosophy of Samba to expose the features of
   the OS within the SMB model. In general whatever file/printer/variable
   expansions/etc make sense to the OS should be acceptable to Samba.
 */


/*******************************************************************
this replaces the normal select() system call
return if some data has arrived on one of the file descriptors
return -1 means error
********************************************************************/
#ifndef HAVE_SELECT
static int
pollfd (int fd)
{
    int r = 0;

#ifdef HAS_RDCHK
    r = rdchk (fd);
#elif defined(TCRDCHK)
    (void) ioctl (fd, TCRDCHK, &r);
#else
    (void) ioctl (fd, FIONREAD, &r);
#endif

    return (r);
}

int
sys_select (int maxfd, fd_set * fds, struct timeval *tval)
{
    fd_set fds2;
    int counter = 0;
    int found = 0;

    FD_ZERO (&fds2);

    while (1)
    {
        int i;
        for (i = 0; i < maxfd; i++)
        {
            if (FD_ISSET (i, fds) && pollfd (i) > 0)
            {
                found++;
                FD_SET (i, &fds2);
            }
        }

        if (found)
        {
            memcpy ((void *) fds, (void *) &fds2, sizeof (fds2));
            return (found);
        }

        if (tval && tval->tv_sec < counter)
            return (0);
        sleep (1);
        counter++;
    }
}

#else /* !NO_SELECT */
int
sys_select (int maxfd, fd_set * fds, struct timeval *tval)
/* cppcheck-suppress syntaxError */
{
#ifdef USE_POLL
    struct pollfd pfd[256];
    int i;
    int maxpoll;
    int timeout;
    int pollrtn;

    maxpoll = 0;
    for (i = 0; i < maxfd; i++)
    {
        if (FD_ISSET (i, fds))
        {
            struct pollfd *pfdp = &pfd[maxpoll++];
            pfdp->fd = i;
            pfdp->events = POLLIN;
            pfdp->revents = 0;
        }
    }

    timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec / 1000) : -1;
    errno = 0;
    do
    {
        pollrtn = poll (&pfd[0], maxpoll, timeout);
    }
    while (pollrtn < 0 && errno == EINTR);

    FD_ZERO (fds);

    for (i = 0; i < maxpoll; i++)
        if (pfd[i].revents & POLLIN)
            FD_SET (pfd[i].fd, fds);

    return pollrtn;
#else /* USE_POLL */

    struct timeval t2;
    int selrtn;

    do
    {
        if (tval)
            memcpy ((void *) &t2, (void *) tval, sizeof (t2));
        errno = 0;
        selrtn = select (maxfd, SELECT_CAST fds, NULL, NULL, tval ? &t2 : NULL);
    }
    while (selrtn < 0 && errno == EINTR);

    return (selrtn);
}
#endif /* USE_POLL */
#endif /* NO_SELECT */

/*******************************************************************
A stat() wrapper that will deal with 64 bit filesizes.
********************************************************************/

int
sys_stat (const char *fname, SMB_STRUCT_STAT * sbuf)
{
    return stat (fname, sbuf);
}

/*******************************************************************
 An lstat() wrapper that will deal with 64 bit filesizes.
********************************************************************/
#if 0
int
sys_lstat (const char *fname, SMB_STRUCT_STAT * sbuf)
{
    return lstat (fname, sbuf);
}

/*******************************************************************
 An fseek() wrapper that will deal with 64 bit filesizes.
********************************************************************/

int
sys_fseek (FILE * fp, SMB_OFF_T offset, int whence)
{
    return fseek (fp, offset, whence);
}

/*******************************************************************
 An ftell() wrapper that will deal with 64 bit filesizes.
********************************************************************/

SMB_OFF_T
sys_ftell (FILE * fp)
{
    return (SMB_OFF_T) ftell (fp);
}
#endif /* 0 */
/*******************************************************************
 An open() wrapper that will deal with 64 bit filesizes.
********************************************************************/

int
sys_open (const char *path, int oflag, mode_t mode)
{
    return open (path, oflag, mode);
}

/*******************************************************************
 An fopen() wrapper that will deal with 64 bit filesizes.
********************************************************************/

FILE *
sys_fopen (const char *path, const char *type)
{
    return fopen (path, type);
}

#if 0
/*******************************************************************
 A readdir wrapper that will deal with 64 bit filesizes.
********************************************************************/

SMB_STRUCT_DIRENT *
sys_readdir (DIR * dirp)
{
    return readdir (dirp);
}

/*******************************************************************
system wrapper for getwd
********************************************************************/
char *
sys_getwd (char *s)
{
    char *wd;
#ifdef HAVE_GETCWD
    wd = (char *) getcwd (s, sizeof (pstring));
#else
    wd = (char *) getwd (s);
#endif
    return wd;
}

/*******************************************************************
chown isn't used much but OS/2 doesn't have it
********************************************************************/

int
sys_chown (const char *fname, uid_t uid, gid_t gid)
{
#ifndef HAVE_CHOWN
    static int done;
    if (!done)
    {
        DEBUG (1, ("WARNING: no chown!\n"));
        done = 1;
    }
#else
    return (chown (fname, uid, gid));
#endif
}
#endif /* 0 */
/**************************************************************************
A wrapper for gethostbyname() that tries avoids looking up hostnames 
in the root domain, which can cause dial-on-demand links to come up for no
apparent reason.
****************************************************************************/
struct hostent *
sys_gethostbyname (const char *name)
{
#ifdef REDUCE_ROOT_DNS_LOOKUPS
    char query[256], hostname[256];
    char *domain;

    /* Does this name have any dots in it? If so, make no change */

    if (strchr (name, '.'))
        return (gethostbyname (name));

    /* Get my hostname, which should have domain name 
       attached. If not, just do the gethostname on the
       original string. 
     */

    gethostname (hostname, sizeof (hostname) - 1);
    hostname[sizeof (hostname) - 1] = 0;
    if ((domain = strchr (hostname, '.')) == NULL)
        return (gethostbyname (name));

    /* Attach domain name to query and do modified query.
       If names too large, just do gethostname on the
       original string.
     */

    if ((strlen (name) + strlen (domain)) >= sizeof (query))
        return (gethostbyname (name));

    slprintf (query, sizeof (query) - 1, "%s%s", name, domain);
    return (gethostbyname (query));
#else /* REDUCE_ROOT_DNS_LOOKUPS */
    return (gethostbyname (name));
#endif /* REDUCE_ROOT_DNS_LOOKUPS */
}

/**************************************************************************
 Wrapper for random().
****************************************************************************/
#if 0
long
sys_random (void)
{
#if defined(HAVE_RANDOM)
    return (long) random ();
#elif defined(HAVE_RAND)
    return (long) rand ();
#else
    DEBUG (0, ("Error - no random function available !\n"));
    exit (1);
#endif
}

/**************************************************************************
 Wrapper for srandom().
****************************************************************************/

void
sys_srandom (unsigned int seed)
{
#if defined(HAVE_SRANDOM)
    srandom (seed);
#elif defined(HAVE_SRAND)
    srand (seed);
#else
    DEBUG (0, ("Error - no srandom function available !\n"));
    exit (1);
#endif
}
#endif /* 0 */
