
/******************************************************************************
**
**  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.
**
******************************************************************************/

/*****************************************************************************
**
**  File:    scan_record.c
**  Date:    March 19, 2002
**
**  Author:  Brian Wotring
**  Purpose: common structures for dealing with scan data.
**
******************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

#include <sys/stat.h>
#include <sys/types.h>

#ifdef WIN32
#include <winsock.h>
#include <time.h>
#endif


#include "utilities.h"
#include "scan_record.h"

#include "string_list.h"
#include "list.h"

#include "filter.h"
#include "configuration.h"


SCAN_RECORD * initialize_scan_record( SCAN_RECORD *scan_record,
                                      osi_uint16 type )
{
    if( scan_record != NULL )
    {
        switch( (int)type )
        {
            case SCAN_RECORD_TYPE_UNIX1:

                memset( scan_record, 0, sizeof( SCAN_RECORD_UNIX1 ) );
                scan_record->type = type;
                break;

            case SCAN_RECORD_TYPE_UNIX2:

                memset( scan_record, 0, sizeof( SCAN_RECORD_UNIX2 ) );
                scan_record->type = type;
                break;

            case SCAN_RECORD_TYPE_WIN32:

                memset( scan_record, 0, sizeof( SCAN_RECORD_WIN32 ) );
                scan_record->type = type;
                break;

            case SCAN_RECORD_TYPE_WINNT:

                memset( scan_record, 0, sizeof( SCAN_RECORD_WINNT ) );
                scan_record->type = type;
                break;

            default:
                break;
        }
    }

    return scan_record;
}

int determine_scan_record_size( SCAN_RECORD *scan_record )
{
    int size = 0;

    if( scan_record != NULL )
    {
        size = determine_scan_record_size_from_type( (int)scan_record->type );
    }

    return size;
}

int determine_scan_record_size_from_type( int type )
{
    int size = 0;

    switch( type )
    {
        case SCAN_RECORD_TYPE_UNIX1:

            size = sizeof( SCAN_RECORD_UNIX1 );
            break;

        case SCAN_RECORD_TYPE_UNIX2:

            size = sizeof( SCAN_RECORD_UNIX2 );
            break;

        case SCAN_RECORD_TYPE_WIN32:

            size = sizeof( SCAN_RECORD_WIN32 );
            break;

        case SCAN_RECORD_TYPE_WINNT:

            size = sizeof( SCAN_RECORD_WINNT );
            break;

        default:
            break;
    }

    return size;
}

char * get_scan_record_path( SCAN_RECORD *scan_record )
{
    char * path = NULL;

    if( scan_record != NULL )
    {
        osi_uint16 type = scan_record->type;

        switch( (int)type )
        {
            case SCAN_RECORD_TYPE_UNIX1:

                path = ( (SCAN_RECORD_UNIX1 *)scan_record )->path;
                break;

            case SCAN_RECORD_TYPE_UNIX2:

                path = ( (SCAN_RECORD_UNIX2 *)scan_record )->path;
                break;

            case SCAN_RECORD_TYPE_WIN32:

                path = ( (SCAN_RECORD_WIN32 *)scan_record )->path;
                break;

            case SCAN_RECORD_TYPE_WINNT:

                path = ( (SCAN_RECORD_WINNT *)scan_record )->path;
                break;

            default:
                break;
        }
    }

    return path;
}

char * get_scan_record_name_from_type( osi_uint16 type )
{
    char * name = "unknown";

    switch( (int)type )
    {
        case SCAN_RECORD_TYPE_UNIX1:

            name = "UNIX1";
            break;

        case SCAN_RECORD_TYPE_UNIX2:

            name = "UNIX2";
            break;

        case SCAN_RECORD_TYPE_WIN32:

            name = "WIN32";
            break;

        case SCAN_RECORD_TYPE_WINNT:

            name = "WINNT";
            break;

        default:
            break;
    }

    return name;
}



void wrap_scan_record( SCAN_RECORD *scan_record )
{
    osi_uint16 type;

    if( scan_record != NULL )
    {
        type = scan_record->type;

        switch( (int)type )
        {
            case SCAN_RECORD_TYPE_UNIX1:
            {
                SCAN_RECORD_UNIX1 *record = (SCAN_RECORD_UNIX1 *)scan_record;

                record->filter 	 	   = htons( record->filter );
                record->checksum_algorithm =htons( record->checksum_algorithm );

                record->device 	 	= HTONLL( record->device );
                record->inode 	 	= HTONLL( record->inode );
                record->permissions	= HTONLL( record->permissions );
                record->links 	 	= HTONLL( record->links );
                record->uid 	 	= HTONLL( record->uid );
                record->gid 	 	= HTONLL( record->gid );
                record->mtime 	 	= HTONLL( record->mtime );
                record->atime 	 	= HTONLL( record->atime );
                record->ctime 	 	= HTONLL( record->ctime );
                record->device_type	= HTONLL( record->device_type );
                record->bytes 	 	= HTONLL( record->bytes );
                record->blocks 	 	= HTONLL( record->blocks );
                record->block_size 	= HTONLL( record->block_size );
            }
                break;

            case SCAN_RECORD_TYPE_UNIX2:
                break;

            case SCAN_RECORD_TYPE_WIN32:
                break;

            case SCAN_RECORD_TYPE_WINNT:
            {
                SCAN_RECORD_WINNT *record = (SCAN_RECORD_WINNT *)scan_record;

                record->filter 	    = htons( record->filter );
                record->checksum_algorithm =htons( record->checksum_algorithm );

                record->device 	 	= HTONLL( record->device );
                record->mtime 	 	= HTONLL( record->mtime );
                record->atime 	 	= HTONLL( record->atime );
                record->ctime 	 	= HTONLL( record->ctime );
                record->bytes 	 	= HTONLL( record->bytes );
                record->attributes  = HTONLL( record->attributes );
            }
                break;

            default:
                break;
        }

        /* we always wrap the type, this might just be */
        /* a SCAN_RECORD structure.                    */

        scan_record->type = htons( scan_record->type );
    }
}

void unwrap_scan_record( SCAN_RECORD *scan_record )
{
    osi_uint16 type;

    if( scan_record != NULL )
    {
        type = ntohs( scan_record->type );

        switch( (int)type )
        {
            case SCAN_RECORD_TYPE_UNIX1:
            {
                SCAN_RECORD_UNIX1 *record = (SCAN_RECORD_UNIX1 *)scan_record;

                record->filter = ntohs( record->filter );
                record->checksum_algorithm = ntohs(record->checksum_algorithm);

                record->device 	 		= NTOHLL( record->device );
                record->inode 	 		= NTOHLL( record->inode );
                record->permissions		= NTOHLL( record->permissions );
                record->links 	 		= NTOHLL( record->links );
                record->uid 	 		= NTOHLL( record->uid );
                record->gid 	 		= NTOHLL( record->gid );
                record->mtime 	 		= NTOHLL( record->mtime );
                record->atime 	 		= NTOHLL( record->atime );
                record->ctime 	 		= NTOHLL( record->ctime );
                record->device_type 	= NTOHLL( record->device_type );
                record->bytes 	 		= NTOHLL( record->bytes );
                record->blocks 	 		= NTOHLL( record->blocks );
                record->block_size  	= NTOHLL( record->block_size );
            }

                break;

            case SCAN_RECORD_TYPE_UNIX2:
                break;

            case SCAN_RECORD_TYPE_WIN32:
                break;

            case SCAN_RECORD_TYPE_WINNT:
            {
                SCAN_RECORD_WINNT *record = (SCAN_RECORD_WINNT *)scan_record;

                record->filter = ntohs( record->filter );
                record->checksum_algorithm = ntohs(record->checksum_algorithm);

                record->device 	 		= NTOHLL( record->device );
                record->mtime 	 		= NTOHLL( record->mtime );
                record->atime 	 		= NTOHLL( record->atime );
                record->ctime 	 		= NTOHLL( record->ctime );
                record->bytes 	 		= NTOHLL( record->bytes );
                record->attributes      = NTOHLL( record->attributes );
            }
                break;

            default:
                break;
        }

        /* we always unwrap the type, this might be just */
        /* a SCAN_RECORD structure.                      */

        scan_record->type = ntohs( scan_record->type );
    }
}

void wrap_scan_results( OSI_SCAN_RESULTS *scan_results )
{
    if( scan_results != NULL )
    {
        scan_results->files_encountered = htonl(
                                scan_results->files_encountered );

        scan_results->files_scanned = htonl( scan_results->files_scanned );

        scan_results->symlinks_encountered = htonl(
                                scan_results->symlinks_encountered );

        scan_results->symlinks_followed = htonl(
                                scan_results->symlinks_followed );

        scan_results->files_unreadable = htonl(
                                scan_results->files_unreadable );

        scan_results->directories_unreadable = htonl(
                                scan_results->directories_unreadable );

        scan_results->symlinks_unreadable = htonl(
                                scan_results->symlinks_unreadable );

        scan_results->start_time = htonl( scan_results->start_time );
        scan_results->stop_time  = htonl( scan_results->stop_time );

        scan_results->record_type = htons( scan_results->record_type );
    }
}

void unwrap_scan_results( OSI_SCAN_RESULTS *scan_results )
{
    if( scan_results != NULL )
    {
        scan_results->files_encountered = ntohl(
                                scan_results->files_encountered );

        scan_results->files_scanned = ntohl(
                                scan_results->files_scanned );

        scan_results->symlinks_encountered = ntohl(
                                scan_results->symlinks_encountered );

        scan_results->symlinks_followed = ntohl(
                                scan_results->symlinks_followed );

        scan_results->files_unreadable = ntohl(
                                scan_results->files_unreadable );

        scan_results->directories_unreadable = ntohl(
                                scan_results->directories_unreadable );

        scan_results->symlinks_unreadable = ntohl(
                                scan_results->symlinks_unreadable );

        scan_results->start_time = ntohl( scan_results->start_time );
        scan_results->stop_time  = ntohl( scan_results->stop_time );

        scan_results->record_type = ntohs( scan_results->record_type );
    }
}

int pack_scan_record( SCAN_RECORD *scan_record, unsigned char *buffer,
                           int buffer_size )
{
    int record_size = 0;
    int packed_size = 0;

    osi_uint16 type;
    unsigned char *dest = buffer;

    if( ( scan_record == NULL ) || ( buffer == NULL ) )
    {
        return packed_size;
    }

    /* make sure we have a big enough buffer. */

    record_size = determine_scan_record_size( scan_record );

    if( record_size > buffer_size )
    {
        return packed_size;
    }

    memcpy( &type, scan_record, sizeof( osi_uint16 ) ); 
    type = ntohs( type );

    switch( (int)type )
    {
        case SCAN_RECORD_TYPE_UNIX1:
        {
            SCAN_RECORD_UNIX1 *r = (SCAN_RECORD_UNIX1 *)scan_record;

            memcpy( dest, &r->type, sizeof( r->type ) );
            dest += sizeof( r->type );

            memcpy( dest, &r->filter, sizeof( r->filter ) );
            dest += sizeof( r->filter );

            memcpy( dest, &r->path, sizeof( r->path ) );
            dest += sizeof( r->path );

            memcpy( dest, &r->checksum, sizeof( r->checksum ) );
            dest += sizeof( r->checksum ); 

            memcpy( dest, &r->checksum_algorithm,
                    sizeof( r->checksum_algorithm ) );
            dest += sizeof( r->checksum_algorithm );

            memcpy( dest, &r->permissions_string,
                    sizeof( r->permissions_string ) );
            dest += sizeof( r->permissions_string );

            memcpy( dest, &r->user, sizeof( r->user ) );
            dest += sizeof( r->user );

            memcpy( dest, &r->group, sizeof( r->group ) );
            dest += sizeof( r->group );

            memcpy( dest, &r->device, sizeof( r->device ) );
            dest += sizeof( r->device );

            memcpy( dest, &r->inode, sizeof( r->inode ) );
            dest += sizeof( r->inode );

            memcpy( dest, &r->permissions, sizeof( r->permissions ) );
            dest += sizeof( r->permissions );

            memcpy( dest, &r->links, sizeof( r->links ) );
            dest += sizeof( r->links );

            memcpy( dest, &r->uid, sizeof( r->uid ) );
            dest += sizeof( r->uid );

            memcpy( dest, &r->gid, sizeof( r->gid ) );
            dest += sizeof( r->gid );

            memcpy( dest, &r->mtime, sizeof( r->mtime ) );
            dest += sizeof( r->mtime );

            memcpy( dest, &r->atime, sizeof( r->atime ) );
            dest += sizeof( r->atime );

            memcpy( dest, &r->ctime, sizeof( r->ctime ) );
            dest += sizeof( r->ctime );

            memcpy( dest, &r->device_type, sizeof( r->device_type ) );
            dest += sizeof( r->device_type );

            memcpy( dest, &r->bytes, sizeof( r->bytes ) );
            dest += sizeof( r->bytes );

            memcpy( dest, &r->blocks, sizeof( r->blocks ) );
            dest += sizeof( r->blocks );

            memcpy( dest, &r->block_size, sizeof( r->block_size ) );
            dest += sizeof( r->block_size );

            packed_size = ( dest - buffer );
            break;
        }

        case SCAN_RECORD_TYPE_UNIX2:
        {
            SCAN_RECORD_UNIX2 *r = (SCAN_RECORD_UNIX2 *)scan_record;

            memcpy( dest, &r->type, sizeof( r->type ) );
            dest += sizeof( r->type );

            memcpy( dest, &r->path, sizeof( r->path ) );
            dest += sizeof( r->path );

            packed_size = ( dest - buffer );
            break;
        }

        case SCAN_RECORD_TYPE_WIN32:
        {
            SCAN_RECORD_WIN32 *r = (SCAN_RECORD_WIN32 *)scan_record;

            memcpy( dest, &r->type, sizeof( r->type ) );
            dest += sizeof( r->type );

            memcpy( dest, &r->path, sizeof( r->path ) );
            dest += sizeof( r->path );

            packed_size = ( dest - buffer );
            break;
        }

        case SCAN_RECORD_TYPE_WINNT:
        {
            SCAN_RECORD_WINNT *r = (SCAN_RECORD_WINNT *)scan_record;

            memcpy( dest, &r->type, sizeof( r->type ) );
            dest += sizeof( r->type );

            memcpy( dest, &r->filter, sizeof( r->filter ) );
            dest += sizeof( r->filter );

            memcpy( dest, &r->path, sizeof( r->path ) );
            dest += sizeof( r->path );

            memcpy( dest, &r->checksum, sizeof( r->checksum ) );
            dest += sizeof( r->checksum );

            memcpy( dest, &r->checksum_algorithm,
                    sizeof( r->checksum_algorithm ) );
            dest += sizeof( r->checksum_algorithm );

            memcpy( dest, &r->owner, sizeof( r->owner ) );
            dest += sizeof( r->owner );

            memcpy( dest, &r->owner_sid, sizeof( r->owner_sid ) );
            dest += sizeof( r->owner_sid );

            memcpy( dest, &r->group, sizeof( r->group ) );
            dest += sizeof( r->group );

            memcpy( dest, &r->group_sid, sizeof( r->group_sid ) );
            dest += sizeof( r->group_sid );

            memcpy( dest, &r->mtime, sizeof( r->mtime ) );
            dest += sizeof( r->mtime );

            memcpy( dest, &r->atime, sizeof( r->atime ) );
            dest += sizeof( r->atime );

            memcpy( dest, &r->ctime, sizeof( r->ctime ) );
            dest += sizeof( r->ctime );
        
            memcpy( dest, &r->bytes, sizeof( r->bytes ) );
            dest += sizeof( r->bytes );

            memcpy( dest, &r->device, sizeof( r->device ) );
            dest += sizeof( r->device ); 

            memcpy( dest, &r->attributes, sizeof( r->attributes ) );
            dest += sizeof( r->attributes );

            packed_size = ( dest - buffer );
            break;
        }

        default:
            break;
    }

    return packed_size;
}

osi_bool unpack_scan_record( SCAN_RECORD *scan_record, 
                             const unsigned char *buffer, int buffer_size )
{
    int record_size = 0;
    unsigned char *source = (unsigned char *)buffer;

    osi_uint16 type;

    if( ( scan_record == NULL ) || ( buffer == NULL ) )
    {
        return FALSE;
    }

    memcpy( &type, buffer, sizeof( osi_uint16 ) );
    type = ntohs( type );

    switch( (int)type )
    {
        case SCAN_RECORD_TYPE_UNIX1:
        {
            SCAN_RECORD_UNIX1 *r = (SCAN_RECORD_UNIX1 *)scan_record;

            memcpy( &r->type, source, sizeof( r->type ) );
            source += sizeof( r->type );

            memcpy( &r->filter, source, sizeof( r->filter ) );
            source += sizeof( r->filter );

            memcpy( &r->path, source, sizeof( r->path ) );
            source += sizeof( r->path );

            memcpy( &r->checksum, source, sizeof( r->checksum ) );
            source += sizeof( r->checksum );

            memcpy( &r->checksum_algorithm, source,
                   sizeof( r->checksum_algorithm ) );
            source += sizeof( r->checksum_algorithm );

            memcpy( &r->permissions_string, source,
                   sizeof( r->permissions_string ) );
            source += sizeof( r->permissions_string );

            memcpy( &r->user, source, sizeof( r->user ) );
            source += sizeof( r->user );

            memcpy( &r->group, source, sizeof( r->group ) );
            source += sizeof( r->group );

            memcpy( &r->device, source, sizeof( r->device ) );
            source += sizeof( r->device );

            memcpy( &r->inode, source, sizeof( r->inode ) );
            source += sizeof( r->inode );

            memcpy( &r->permissions, source, sizeof( r->permissions ) );
            source += sizeof( r->permissions );

            memcpy( &r->links, source, sizeof( r->links ) );
            source += sizeof( r->links );

            memcpy( &r->uid, source, sizeof( r->uid ) );
            source += sizeof( r->uid );

            memcpy( &r->gid, source, sizeof( r->gid ) );
            source += sizeof( r->gid );

            memcpy( &r->mtime, source, sizeof( r->mtime ) );
            source += sizeof( r->mtime );

            memcpy( &r->atime, source, sizeof( r->atime ) );
            source += sizeof( r->atime );

            memcpy( &r->ctime, source, sizeof( r->ctime ) );
            source += sizeof( r->ctime );

            memcpy( &r->device_type, source, sizeof( r->device_type ) );
            source += sizeof( r->device_type );

            memcpy( &r->bytes, source, sizeof( r->bytes ) );
            source += sizeof( r->bytes );

            memcpy( &r->blocks, source, sizeof( r->blocks ) );
            source += sizeof( r->blocks );

            memcpy( &r->block_size, source, sizeof( r->block_size ) );
            source += sizeof( r->block_size );

            break;
        }

        case SCAN_RECORD_TYPE_UNIX2:
        {
            SCAN_RECORD_UNIX2 *r = (SCAN_RECORD_UNIX2 *)scan_record;

            memcpy( &r->type, source, sizeof( r->type ) );
            source += sizeof( r->type );

            memcpy( &r->path, source, sizeof( r->path ) );
            source += sizeof( r->path );

            break;
        }

        case SCAN_RECORD_TYPE_WIN32:
        {
            SCAN_RECORD_WIN32 *r = (SCAN_RECORD_WIN32 *)scan_record;

            memcpy( &r->type, source, sizeof( r->type ) );
            source += sizeof( r->type );

            memcpy( &r->path, source, sizeof( r->path ) );
            source += sizeof( r->path );

            break;
        }

        case SCAN_RECORD_TYPE_WINNT:
        {
            SCAN_RECORD_WINNT *r = (SCAN_RECORD_WINNT *)scan_record;

            memcpy( &r->type, source, sizeof( r->type ) );
            source += sizeof( r->type );

            memcpy( &r->filter, source, sizeof( r->filter ) );
            source += sizeof( r->filter );

            memcpy( &r->path, source, sizeof( r->path ) );
            source += sizeof( r->path );

            memcpy( &r->checksum, source, sizeof( r->checksum ) );
            source += sizeof( r->checksum );

            memcpy( &r->checksum_algorithm, source,
                    sizeof( r->checksum_algorithm ) );
            source += sizeof( r->checksum_algorithm );

            memcpy( &r->owner, source, sizeof( r->owner ) );
            source += sizeof( r->owner );

            memcpy( &r->owner_sid, source, sizeof( r->owner_sid ) );
            source += sizeof( r->owner_sid );

            memcpy( &r->group, source, sizeof( r->group ) );
            source += sizeof( r->group );

            memcpy( &r->group_sid, source, sizeof( r->group_sid ) );
            source += sizeof( r->group_sid );

            memcpy( &r->mtime, source, sizeof( r->mtime ) );
            source += sizeof( r->mtime );

            memcpy( &r->atime, source, sizeof( r->atime ) );
            source += sizeof( r->atime );

            memcpy( &r->ctime, source, sizeof( r->ctime ) );
            source += sizeof( r->ctime );

            memcpy( &r->bytes, source, sizeof( r->bytes ) );
            source += sizeof( r->bytes );

            memcpy( &r->device, source, sizeof( r->device ) );
            source += sizeof( r->device );

            memcpy( &r->attributes, source, sizeof( r->attributes ) );
            source += sizeof( r->attributes );

            break;
        }

        default:
            break;
    }

    return TRUE;
}


void print_scan_record( SCAN_RECORD *scan_record )
{
    if( scan_record != NULL )
    {
        time_t m_time;
        time_t a_time;
        time_t c_time;

        switch( (int)scan_record->type )
        {
            case SCAN_RECORD_TYPE_UNIX1:
            {
                SCAN_RECORD_UNIX1 *record = (SCAN_RECORD_UNIX1 *)scan_record;

                fprintf( stdout, "\n-------- begin scan record -------\n\n" );

                fprintf( stdout, "file: %s\n", record->path );
                fprintf( stdout, "record type: UNIX1\n" );
                fprintf( stdout, "checksum: %s\n", record->checksum );
                fprintf( stdout, "checksum algorithm: %s\n",
                   get_hash_name_from_type( (int)record->checksum_algorithm ) );

                fprintf( stdout, "permissions: %s\n",
                         record->permissions_string );

                fprintf( stdout, "user: %s\n", record->user );
                fprintf( stdout, "group: %s\n", record->group );
                fprintf( stdout, "device: %llu\n", record->device );
                fprintf( stdout, "inode: %llu\n", record->inode );
                fprintf( stdout, "mode: %llu\n", record->permissions );
                fprintf( stdout, "links: %llu\n", record->links );
                fprintf( stdout, "uid: %llu\n", record->uid );
                fprintf( stdout, "gid: %llu\n", record->gid );

                m_time = (time_t)record->mtime;
                a_time = (time_t)record->atime;
                c_time = (time_t)record->ctime;

                fprintf( stdout, "mtime: %s", ctime( &m_time ) );
                fprintf( stdout, "atime: %s", ctime( &a_time ) );
                fprintf( stdout, "ctime: %s", ctime( &c_time ) );

                fprintf( stdout, "device_type: %llu\n", record->device_type );
                fprintf( stdout, "bytes: %llu\n", record->bytes );
                fprintf( stdout, "blocks: %llu\n", record->blocks );
                fprintf( stdout, "block_size: %llu\n", record->block_size );
            }

                break;

            case SCAN_RECORD_TYPE_UNIX2:
                break;

            case SCAN_RECORD_TYPE_WIN32:
                break;

            case SCAN_RECORD_TYPE_WINNT:
            {
                SCAN_RECORD_WINNT *record = (SCAN_RECORD_WINNT *)scan_record;

                fprintf( stdout, "\n-------- begin scan record -------\n\n" );

                fprintf( stdout, "file: %s\n", record->path );
                fprintf( stdout, "record type: WINNT\n" );
                fprintf( stdout, "filter: %llu\n", record->filter );
                fprintf( stdout, "checksum: %s\n", record->checksum );

                fprintf( stdout, "owner: %s\n", record->owner );
                fprintf( stdout, "owner_sid: %s\n", record->owner_sid );
                fprintf( stdout, "group: %s\n", record->group );
                fprintf( stdout, "group_sid: %s\n", record->group_sid );

                fprintf( stdout, "checksum algorithm: %s\n",
                  get_hash_name_from_type( (int)record->checksum_algorithm ) );

                fprintf( stdout, "device: %llu\n", record->device );
                fprintf( stdout, "attributes: %llu\n", record->attributes );

                m_time = (time_t)record->mtime;
                a_time = (time_t)record->atime;
                c_time = (time_t)record->ctime;

                fprintf( stdout, "mtime: %s", ctime( &m_time ) );
                fprintf( stdout, "atime: %s", ctime( &a_time ) );
                fprintf( stdout, "ctime: %s", ctime( &c_time ) );

                fprintf( stdout, "bytes: %llu\n", record->bytes );
            }
                break;

            default:

                fprintf( stdout, "unknown record type!\n" );
                break;
        }
    }
}

void print_scan_results( OSI_SCAN_RESULTS *results )
{
    if( results )
    {
        fprintf( stdout, "\n\n" );
        fprintf( stdout, "            record type: %s\n\n",
                 get_scan_record_name_from_type( results->record_type ) );

        fprintf( stdout, "      files encountered: %d\n",
                 results->files_encountered );

        fprintf( stdout, "          files scanned: %d\n\n",
                 results->files_scanned );

        fprintf( stdout, "   symlinks encountered: %d\n",
                 results->symlinks_encountered );

        fprintf( stdout, "      symlinks followed: %d\n\n",
                 results->symlinks_followed );

        fprintf( stdout, "       files unreadable: %d\n",
                 results->files_unreadable );

        fprintf( stdout, " directories unreadable: %d\n",
                 results->directories_unreadable );

        fprintf( stdout, "    symlinks unreadable: %d\n\n",
                 results->symlinks_unreadable );

        fprintf( stdout, "           scan started: %s",
                 ctime( (time_t *)&( results->start_time ) ) );

        fprintf( stdout, "          scan finished: %s\n\n",
                 ctime( (time_t *)&( results->stop_time ) ) );
    }
}

void get_win32_file_attr_delta_string( osi_uint64 before, osi_uint64 after,
                                       char *buffer, int buffer_size )
{
    int index;
    osi_uint64 deltas;

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

    buffer[0] = '\0';
    deltas = ( before ^ after );

    /* now go through and figure out if each delta was added or is missing. */

    
    for( index = 0; win32_attr_descriptions[index].word != NULL; index++ )
    {
        if( deltas & win32_attr_descriptions[index].type )
        {
            if( before & win32_attr_descriptions[index].type )
            {
                osi_strlcat( buffer, "-", buffer_size );
                osi_strlcat( buffer, win32_attr_descriptions[index].word,
                             buffer_size );

                osi_strlcat( buffer, ",", buffer_size );
            }

            else
            {
               osi_strlcat( buffer, "+", buffer_size );
               osi_strlcat( buffer, win32_attr_descriptions[index].word,
                            buffer_size );

               osi_strlcat( buffer, ",", buffer_size );
            }
        }
    }

    /* remove last comma. */

    if( strlen( buffer ) > 0 )
    {
        buffer[strlen(buffer)-1] = '\0';
    }
}
