
/******************************************************************************
**
**  Copyright (C) 2002  - the shmoo group -
**
**  This program is free software; you can redistribute it and/or
**  modify it, however, you cannot sell it.
**
**  This program 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.
**
**  You should have received a copy of the license attached to the
**  use of this software.  If not, visit www.shmoo.com/osiris for
**  details.
**
******************************************************************************/

/*****************************************************************************
**
**    The Shmoo Group (TSG)
**
**    File:      fileapi.c
**    Author:    Brian Wotring
**
**    Date:      May 14, 2002
**    Project:   osiris
**
******************************************************************************/

#include "libosiris.h"

#ifndef WIN32
#include <unistd.h>
#include <pwd.h>
#else
#include <winbase.h>
#include <shlobj.h>
#endif

#include <errno.h>
#include "fileapi.h"


int osi_create_directory( const char *filepath )
{
    if( filepath != NULL )
    {
#ifdef WIN32
        if( CreateDirectory( filepath, NULL ) != FALSE )
        {
            return OSI_FILE_OK;
        }
#else
        mode_t mode = S_IRWXU;

        if( mkdir( filepath, mode ) == 0 )
        {
            return OSI_FILE_OK;
        }
#endif
    }

    return fileapi_get_last_error();
}

int osi_create_subdirectory( const char *rootpath, const char *directory )
{
    if( ( rootpath != NULL ) && ( directory != NULL ) )
    {
        if( osi_directory_exists( rootpath ) )
        {
            char path[MAX_PATH_LENGTH];
            char path_separator[2] = { PATH_SEPARATOR, '\0' };

            osi_strlcpy( path, rootpath, sizeof( path ) );
            osi_strlcat( path, path_separator, sizeof( path ) );
            osi_strlcat( path, directory, sizeof( path ) );

            return osi_create_directory( path );
        }

        else
        {
            return OSI_ERROR_PATH_NOT_FOUND;
        }
    }

    return fileapi_get_last_error();
}

int osi_remove_directory( const char *filepath )
{
    if( filepath != NULL )
    {
#ifdef WIN32
        if( RemoveDirectory( filepath ) != FALSE )
        {
            return OSI_FILE_OK;
        }
#else
        if( rmdir( filepath ) == 0 )
        {
            return OSI_FILE_OK;
        }
#endif
    }

    return fileapi_get_last_error();
}

osi_bool osi_file_exists( const char *filepath )
{
    osi_bool result = FALSE;

    if( filepath != NULL )
    {
        struct stat file_stats;

#ifdef WIN32
        if( stat( filepath, &file_stats ) == 0 )
#else
        if( lstat( filepath, &file_stats ) == 0 )
#endif
        {
            result = TRUE;
        }
    }

    return result;
}

osi_bool osi_directory_exists( const char *filepath )
{
    osi_bool result = FALSE;

    if( filepath != NULL )
    {
        struct stat file_stats;

#ifdef WIN32
        if( stat( filepath, &file_stats ) == 0 )
        {
            if( ( file_stats.st_mode & S_IFMT ) == S_IFDIR )
            {
                result = TRUE;
            }
        }
#else
        if( lstat( filepath, &file_stats ) == 0 )
        {
            if( S_ISDIR( file_stats.st_mode ) )
            {
                result = TRUE;
            }
        }
#endif

    }

    return result;
}

osi_bool osi_subdirectory_exists( const char *rootpath, const char *directory )
{
    osi_bool result = FALSE;

    if( ( rootpath != NULL ) && ( directory != NULL ) )
    {
        char path[MAX_PATH_LENGTH];
        char path_separator[2] = { PATH_SEPARATOR, '\0' };

        osi_strlcpy( path, rootpath, sizeof( path ) );
        osi_strlcat( path, path_separator, sizeof( path ) );
        osi_strlcat( path, directory, sizeof( path ) );

        if( osi_directory_exists( path ) )
        {
            result = TRUE;
        }
    }

    return result;
}


osi_bool osi_open_directory( const char *filepath, OSI_DIRECTORY *directory )
{
    char path[MAX_PATH_LENGTH];
    osi_bool result = FALSE;

    if( ( filepath == NULL ) || ( directory == NULL ) )
    {
        return FALSE;
    }

    memset( directory, 0, sizeof( OSI_DIRECTORY ) );

#ifdef WIN32

    /* for windows, we have to add a wildcard before opening */
    /* the directory.                                        */

    osi_strlcpy( path, filepath, sizeof( path ) );
    osi_strlcat( path, "\\*", sizeof( path ) );

    directory->handle = FindFirstFile( path, &( directory->file ) );

    if( directory->handle != INVALID_HANDLE_VALUE )
    {
        osi_strlcpy( directory->path, filepath, sizeof( directory->path ) );

        osi_strlcpy( directory->filename, directory->file.cFileName,
                     sizeof( directory->filename ) );

        result = TRUE;
    }
#else
    if( ( directory->handle = opendir( filepath ) ) != NULL )
    {
        if( ( directory->file = readdir( directory->handle ) ) != NULL )
        {
            osi_strlcpy( directory->path, filepath, sizeof( directory->path ) );

            osi_strlcpy( directory->filename, directory->file->d_name,
                         sizeof( directory->filename ) );

            result = TRUE;
        }
    }
#endif

    return result;
}

osi_bool osi_close_directory( OSI_DIRECTORY *directory )
{
    osi_bool result = FALSE;

    if( directory != NULL )
    {
#ifdef WIN32
        FindClose( directory->handle );
#else
        if( directory->handle != NULL )
        {
            closedir( directory->handle );
        }

        if( directory->dd_fd )
        {
            close( directory->dd_fd );
            directory->dd_fd = 0;
        }
#endif
        directory->handle = NULL;
        result = TRUE;
    }

    return result;
}

#ifndef WIN32

osi_bool osi_directory_set_fd( OSI_DIRECTORY *directory, int fd )
{
    if( ( directory == NULL ) || ( fd <= 0 ) )
    {
        return FALSE;
    }

    /* we are using an fd, so we make sure our handle is set */
    /* to NULL, close it if it is not.                       */

    if( directory->handle != NULL )
    {
        osi_close_directory( directory );
    }

    directory->handle = NULL;
    directory->dd_fd = fd;
    directory->dd_len = sizeof( directory->buffer );

    return TRUE;
}

#endif


int osi_create_file( const char *filepath, mode_t mode )
{
    int result = OSI_ERROR_NULL_ARGUMENT;

    if( filepath != NULL )
    {
        FILE *new_file;

        if( osi_file_exists( filepath ) )
        {
            return OSI_ERROR_FILE_EXISTS;
        }

        new_file = osi_fopen( filepath, "w", mode );

        if( new_file != NULL )
        {
            result = OSI_FILE_OK;
            fclose( new_file );
        }

        else
        {
            result = fileapi_get_last_error();
        }
    }

    return result;
}

int osi_remove_file( const char *filepath )
{
    if( filepath != NULL )
    {
#ifdef WIN32
        if( DeleteFile( filepath ) != FALSE )
        {
            return OSI_FILE_OK;
        }
#else
        if( unlink( filepath ) == 0 )
        {
            return OSI_FILE_OK;
        }
#endif
    }

    return fileapi_get_last_error();
}

osi_bool osi_get_next_file( OSI_DIRECTORY *directory )
{
    osi_bool result = FALSE;

    if( directory == NULL )
    {
        return FALSE;
    }

    if( ( directory->handle == NULL ) && ( directory->dd_fd <= 0 ) )
    {
        return FALSE;
    }

#ifdef WIN32

    if( FindNextFile( directory->handle, &( directory->file ) ) )
    {
        osi_strlcpy( directory->filename, directory->file.cFileName,
                     sizeof( directory->filename ) );

        result = TRUE;
    }

#else

    /* if we are using DIR structs, use readdir */

    if( directory->handle != NULL )
    {
        if( ( directory->file = readdir( directory->handle ) ) != NULL )
        {
            result = TRUE;
        }
    }

    /* otherwise, we do it by using getdirentries. */

    if( directory->dd_fd > 0 )
    {
        if( osi_readdir( directory ) )
        {
            result = TRUE;
        }
    }

    if( result == TRUE )
    {
        osi_strlcpy( directory->filename, directory->file->d_name,
                     sizeof( directory->filename ) );
    }

#endif

    return result;
}

#ifndef WIN32

struct dirent * osi_readdir( OSI_DIRECTORY *d )
{
#ifdef HAVE_GETDIRENTRIES
    register struct dirent *dp;

    if( d == NULL )
    {
        return NULL;
    }

    for(;;)
    {
        if( d->dd_loc == 0 )
        {
            d->dd_size = getdirentries( d->dd_fd, d->buffer,
                                        d->dd_len, &d->dd_seek );
        }

        if( d->dd_size <= 0  )
        {
            return NULL;
        }

        dp = (struct dirent *)(d->buffer + d->dd_loc );

        if( dp == NULL )
        {
            return NULL;
        }

        if( dp->d_reclen <= 0 || dp->d_reclen > d->dd_len + 1 - d->dd_loc )
        {
            return NULL;
        }

        d->dd_loc += dp->d_reclen;

        if( dp->d_ino == 0 )
        {
            continue;
        }

        d->file = dp;
        return dp;
    }

#endif /* HAVE_GETDIRENTRIES */

    return NULL;
}

#endif

int fileapi_get_last_error()
{
    int code = OSI_ERROR_UNKNOWN;

#ifdef WIN32
    switch( GetLastError() )
    {
        case ERROR_FILE_NOT_FOUND:
        code = OSI_ERROR_FILE_NOT_FOUND;
        break;

        case ERROR_PATH_NOT_FOUND:
        code = OSI_ERROR_PATH_NOT_FOUND;
        break;

        case ERROR_ACCESS_DENIED:
        code = OSI_ERROR_ACCESS_DENIED;
        break;

        case ERROR_SHARING_VIOLATION:
        code = OSI_ERROR_SHARING_VIOLATION;
        break;

        case ERROR_WRITE_PROTECT:
        code = OSI_ERROR_WRITE_PROTECTED;
        break;

        case ERROR_DIR_NOT_EMPTY:
        code = OSI_ERROR_DIRECTORY_NOT_EMPTY;
        break;

        case ERROR_ALREADY_EXISTS:
        case ERROR_FILE_EXISTS:
        code = OSI_ERROR_FILE_EXISTS;
        break;

        case ERROR_DISK_FULL:
        code = OSI_ERROR_DISK_FULL;
        break;

        default:
        code = OSI_ERROR_UNKNOWN;
        break;
    }
#else
    switch( errno )
    {
        case ENAMETOOLONG:
        code = OSI_ERROR_INVALID_PATH;
        break;

        case EACCES:
        code = OSI_ERROR_ACCESS_DENIED;
        break;

        case EROFS:
        code = OSI_ERROR_WRITE_PROTECTED;
        break;

        case EEXIST:
        code = OSI_ERROR_FILE_EXISTS;
        break;

        case ENOSPC:
        code = OSI_ERROR_DISK_FULL;
        break;

        case EIO:
        code = OSI_ERROR_IO_ERROR;
        break;

        default:
        code = OSI_ERROR_UNKNOWN;
        break;
    }
#endif

    return code;
}

osi_bool osi_file_is_regular_file( const char *filepath )
{
    osi_bool result = FALSE;

    if( filepath != NULL )
    {
        struct stat file_stats;

        if( stat( filepath, &file_stats ) == 0 )
        {

#ifdef WIN32
            if( ( file_stats.st_mode & S_IFMT ) == S_IFREG )
#else
            if( S_ISREG( file_stats.st_mode ) )
#endif
            {
                result = TRUE;
            }
        }
    }

    return result;
}

osi_bool osi_file_is_directory( const char *filepath, struct stat *file_stats )
{
    osi_bool result = FALSE;

    struct stat new_stats;
    struct stat *stats;

    if( filepath != NULL )
    {
        /* if we weren't given stats, get them. */

        if( file_stats == NULL )
        {
            if( stat( filepath, &new_stats ) != 0 )
            {
                return FALSE;
            }

            stats = &new_stats;
        }

        else
        {
            stats = file_stats;
        }

#ifdef WIN32
        if( ( stats->st_mode & S_IFMT ) == S_IFDIR )
#else
        if( S_ISDIR( stats->st_mode ) )
#endif
        {
                result = TRUE;
        }
    }

    return result;
}


osi_bool osi_get_user_home_directory( char *buffer, int buffer_size )
{
    osi_bool result = FALSE;

#ifdef WIN32

    char path[MAX_PATH_LENGTH];

    if( SHGetSpecialFolderPath( NULL, path, CSIDL_APPDATA, TRUE ) == TRUE )
    {
        osi_strlcpy( buffer, path, buffer_size );
        return TRUE;
    }

#else

    struct passwd *pw;

    if( buffer == NULL || buffer_size <= 0 )
    {
        return result;
    }

    pw = getpwuid( getuid() );

    if( !pw )
    {
        return result;
    }

    osi_strlcpy( buffer, pw->pw_dir, buffer_size );
    result = TRUE;

#endif

    return result;
}

osi_bool osi_get_osiris_home_directory( char *buffer, int buffer_size )
{
    osi_bool found = FALSE;
    
    /* for windows, we look in the windows directory, for   */
    /* the unix platforms, we look in /usr/local, and /etc. */
    
#ifdef WIN32
    
    char path[256]  = "";

    LPTSTR info     = NULL;
    DWORD info_size = sizeof( path );
    
    info = path;
    
    if( GetWindowsDirectory( info, info_size ) != 0 )
    {
        osi_strlcpy( buffer, info, buffer_size );
        osi_strlcat( buffer, "\\", buffer_size );
        osi_strlcat( buffer, "osiris", buffer_size );
        
        if( osi_directory_exists( buffer ) )
        {
            found = TRUE;
        }
    }
    
#else

    if( osi_directory_exists( OSIRIS_ROOT_1 ) )
    {
        osi_strlcpy( buffer, OSIRIS_ROOT_1, buffer_size );
        found = TRUE;
    }
    
    else if( osi_directory_exists( OSIRIS_ROOT_2 ) )
    {
        osi_strlcpy( buffer, OSIRIS_ROOT_2, buffer_size );
        found = TRUE;
    }
    
#endif

    return found;
}


osi_bool osi_create_osiris_home_directory()
{

#ifdef WIN32

    char path[256]  = "";
    char buffer[MAX_PATH_LENGTH] = "";

    LPTSTR info     = NULL;
    DWORD info_size = sizeof( path );

    info = path;

    if( GetWindowsDirectory( info, info_size ) != 0 )
    {
        osi_strlcpy( buffer, info, sizeof( buffer ) );
        osi_strlcat( buffer, "\\", sizeof( buffer ) );
        osi_strlcat( buffer, "osiris", sizeof( buffer ) );

        if( osi_create_directory( buffer ) == OSI_FILE_OK )
        {
            return TRUE;
        }
    }

#else

    if( osi_create_directory( OSIRIS_ROOT_1 ) == OSI_FILE_OK )
    {
        return TRUE;
    }

    if( osi_create_directory( OSIRIS_ROOT_2 ) == OSI_FILE_OK )
    {
        return TRUE;
    }

#endif

    return FALSE;
}

osi_bool osi_osiris_home_directory_exists()
{

#ifdef WIN32

    char path[256]  = "";
    char buffer[MAX_PATH_LENGTH] = "";

    LPTSTR info     = NULL;
    DWORD info_size = sizeof( path );

    info = path;

    if( GetWindowsDirectory( info, info_size ) != 0 )
    {
        osi_strlcpy( buffer, info, sizeof( buffer ) );
        osi_strlcat( buffer, "\\", sizeof( buffer ) );
        osi_strlcat( buffer, "osiris", sizeof( buffer ) );

        if( osi_directory_exists( buffer ) )
        {
            return TRUE;
        }
    }

#else

    if( osi_directory_exists( OSIRIS_ROOT_1 ) )
    {
        return TRUE;
    }

    if( osi_directory_exists( OSIRIS_ROOT_2 ) )
    {
        return TRUE;
    }

#endif

    return FALSE;
}





