Beispiel #1
0
static void file_dirscan_impl( OBJECT * dir, scanback func, void * closure )
{
    file_info_t * const d = file_query( dir );
    if ( !d || !d->is_dir )
        return;

    /* Lazy collect the directory content information. */
    if ( list_empty( d->files ) )
    {
        if ( DEBUG_BINDSCAN )
            printf( "scan directory %s\n", object_str( d->name ) );
        if ( file_collect_dir_content_( d ) < 0 )
            return;
    }

    /* OS specific part of the file_dirscan operation. */
    file_dirscan_( d, func, closure );

    /* Report the collected directory content. */
    {
        LISTITER iter = list_begin( d->files );
        LISTITER const end = list_end( d->files );
        for ( ; iter != end; iter = list_next( iter ) )
        {
            OBJECT * const path = list_item( iter );
            file_info_t const * const ffq = file_query( path );
            /* The only way a file_query() call can fail is if its internal OS
             * file information gathering API (e.g. stat()) failed. If that
             * happens we should treat the file as if it no longer exists. We
             * then request the raw cached file_info_t structure for that file
             * and use the file name from there.
             */
            file_info_t const * const ff = ffq ? ffq : file_info( path );
            /* Using a file name read from a file_info_t structure allows OS
             * specific implementations to store some kind of a normalized file
             * name there. Using such a normalized file name then allows us to
             * correctly recognize different file paths actually identifying the
             * same file. For instance, an implementation may:
             *  - convert all file names internally to lower case on a case
             *    insensitive file system
             *  - convert the NTFS paths to their long path variants as that
             *    file system each file system entity may have a long and a
             *    short path variant thus allowing for many different path
             *    strings identifying the same file.
             */
            (*func)( closure, ff->name, 1 /* stat()'ed */, &ff->time );
        }
    }
}
Beispiel #2
0
int file_time( OBJECT * const path, timestamp * const time )
{
    file_info_t const * const ff = file_query( path );
    if ( !ff ) return -1;
    timestamp_copy( time, &ff->time );
    return 0;
}
Beispiel #3
0
int
file_time(
    OBJECT * filename,
    time_t * time )
{
    file_info_t * ff = file_query( filename );
    if ( !ff ) return -1;
    *time = ff->time;
    return 0;
}
Beispiel #4
0
int file_collect_dir_content_( file_info_t * const d )
{
    LIST * files = L0;
    PATHNAME f;
    int n;
    STRUCT_DIRENT ** namelist;
    STRUCT_DIRENT * dirent;
    string path[ 1 ];
    char const * dirstr;

    assert( d );
    assert( d->is_dir );
    assert( list_empty( d->files ) );

    dirstr = object_str( d->name );

    memset( (char *)&f, '\0', sizeof( f ) );
    f.f_dir.ptr = dirstr;
    f.f_dir.len = strlen( dirstr );

    if ( !*dirstr ) dirstr = ".";

    if ( -1 == ( n = scandir( dirstr, &namelist, NULL, alphasort ) ) )
        return -1;

    string_new( path );
    while ( n-- )
    {
        OBJECT * name;
        dirent = namelist[ n ];
        f.f_base.ptr = dirent->d_name
        #ifdef old_sinix
            - 2  /* Broken structure definition on sinix. */
        #endif
            ;
        f.f_base.len = strlen( f.f_base.ptr );

        string_truncate( path, 0 );
        path_build( &f, path );
        name = object_new( path->value );
        /* Immediately stat the file to preserve invariants. */
        if ( file_query( name ) )
            files = list_push_back( files, name );
        else
            object_free( name );
        free( dirent );
    }
    string_free( path );

    free( namelist );

    d->files = files;
    return 0;
}
Beispiel #5
0
file_archive_info_t * file_archive_query( OBJECT * const path )
{
    int found;
    file_archive_info_t * const archive = file_archive_info( path, &found );
    file_info_t * file = file_query( path );

    if ( !( file && file->is_file ) )
    {
        return 0;
    }

    archive->file = file;


    return archive;
}
Beispiel #6
0
int file_is_file( OBJECT * filename )
{
    file_info_t * ff = file_query( filename );
    if ( !ff ) return -1;
    return ff->is_file;
}
Beispiel #7
0
void file_dirscan( OBJECT * dir, scanback func, void * closure )
{
    PROFILE_ENTER( FILE_DIRSCAN );

    file_info_t * d = 0;

    d = file_query( dir );

    if ( !d || !d->is_dir )
    {
        PROFILE_EXIT( FILE_DIRSCAN );
        return;
    }

    if ( ! d->files )
    {
        LIST* files = L0;
        PATHNAME f;
        DIR *dd;
        STRUCT_DIRENT *dirent;
        string filename[1];
        const char * dirstr = object_str( dir );

        /* First enter directory itself */

        memset( (char *)&f, '\0', sizeof( f ) );

        f.f_dir.ptr = dirstr;
        f.f_dir.len = strlen( dirstr );

        dirstr = *dirstr ? dirstr : ".";

        /* Now enter contents of directory. */

        if ( !( dd = opendir( dirstr ) ) )
        {
            PROFILE_EXIT( FILE_DIRSCAN );
            return;
        }

        if ( DEBUG_BINDSCAN )
            printf( "scan directory %s\n", dirstr );

        string_new( filename );
        while ( ( dirent = readdir( dd ) ) )
        {
            OBJECT * filename_obj;
            # ifdef old_sinix
            /* Broken structure definition on sinix. */
            f.f_base.ptr = dirent->d_name - 2;
            # else
            f.f_base.ptr = dirent->d_name;
            # endif
            f.f_base.len = strlen( f.f_base.ptr );

            string_truncate( filename, 0 );
            path_build( &f, filename, 0 );

            filename_obj = object_new( filename->value );
            files = list_new( files, filename_obj );
            file_query( filename_obj );
        }
        string_free( filename );

        closedir( dd );

        d->files = files;
    }

    /* Special case / : enter it */
    {
        if ( strcmp( object_str( d->name ), "/" ) == 0 )
            (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
    }

    /* Now enter contents of directory */
    if ( d->files )
    {
        LIST * files = d->files;
        while ( files )
        {
            file_info_t * ff = file_info( files->value );
            (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
            files = list_next( files );
        }
    }

    PROFILE_EXIT( FILE_DIRSCAN );
}
Beispiel #8
0
OBJECT *
search(
    OBJECT * target,
    time_t *time,
    OBJECT * * another_target,
    int file
)
{
    PATHNAME f[1];
    LIST   * varlist;
    string   buf[1];
    int      found = 0;
    /* Will be set to 1 if target location is specified via LOCATE. */
    int      explicitly_located = 0;
    OBJECT * boundname = 0;
    OBJECT * varname;

    if ( another_target )
        *another_target = 0;

    if (! explicit_bindings )
        explicit_bindings = hashinit( sizeof(BINDING),
                                      "explicitly specified locations");

    string_new( buf );
    /* Parse the filename */

    path_parse( object_str( target ), f );

    f->f_grist.ptr = 0;
    f->f_grist.len = 0;

    varname = object_new( "LOCATE" );
    varlist = var_get( varname );
    object_free( varname );
    if ( varlist )
    {
        OBJECT * key;
        f->f_root.ptr = object_str( varlist->value );
        f->f_root.len = strlen( object_str( varlist->value ) );

        path_build( f, buf, 1 );

        if ( DEBUG_SEARCH )
            printf( "locate %s: %s\n", object_str( target ), buf->value );

        explicitly_located = 1;

        key = object_new( buf->value );
        timestamp( key, time );
        object_free( key );
        found = 1;
    }
    else if ( ( varname = object_new( "SEARCH" ),
                varlist = var_get( varname ),
                object_free( varname ),
                varlist ) )
    {
        while ( varlist )
        {
            BINDING b, *ba = &b;
            file_info_t *ff;
            OBJECT * key;
            OBJECT * test_path;

            f->f_root.ptr = object_str( varlist->value );
            f->f_root.len = strlen( object_str( varlist->value ) );

            string_truncate( buf, 0 );
            path_build( f, buf, 1 );

            if ( DEBUG_SEARCH )
                printf( "search %s: %s\n", object_str( target ), buf->value );

            test_path = object_new( buf->value );
            key = path_as_key( test_path );
            object_free( test_path );
            ff = file_query( key );
            timestamp( key, time );

            b.binding = key;

            if ( hashcheck( explicit_bindings, (HASHDATA**)&ba ) )
            {
                if ( DEBUG_SEARCH )
                    printf(" search %s: found explicitly located target %s\n",
                           object_str( target ), object_str( ba->target ) );
                if ( another_target )
                    *another_target = ba->target;
                found = 1;
                object_free( key );
                break;
            }
            else if ( ff && ff->time )
            {
                if ( !file || ff->is_file )
                {
                    found = 1;
                    object_free( key );
                    break;
                }
            }
            object_free( key );

            varlist = list_next( varlist );
        }
    }

    if ( !found )
    {
        /* Look for the obvious */
        /* This is a questionable move.  Should we look in the */
        /* obvious place if SEARCH is set? */
        OBJECT * key;

        f->f_root.ptr = 0;
        f->f_root.len = 0;

        string_truncate( buf, 0 );
        path_build( f, buf, 1 );

        if ( DEBUG_SEARCH )
            printf( "search %s: %s\n", object_str( target ), buf->value );

        key = object_new( buf->value );
        timestamp( key, time );
        object_free( key );
    }

    boundname = object_new( buf->value );
    string_free( buf );

    if ( explicitly_located )
    {
        BINDING b;
        BINDING * ba = &b;
        OBJECT * key = path_as_key( boundname );
        b.binding = key;
        b.target = target;
        /* CONSIDER: we probably should issue a warning is another file
           is explicitly bound to the same location. This might break
           compatibility, though. */
        if ( !hashenter( explicit_bindings, (HASHDATA * *)&ba ) )
        {
            object_free( key );
        }
    }

    /* prepare a call to BINDRULE if the variable is set */
    call_bind_rule( target, boundname );

    return boundname;
}
Beispiel #9
0
void file_dirscan( char * dir, scanback func, void * closure )
{
    PROFILE_ENTER( FILE_DIRSCAN );

    file_info_t * d = 0;

    dir = short_path_to_long_path( dir );

    /* First enter directory itself */

    d = file_query( dir );

    if ( !d || !d->is_dir )
    {
        PROFILE_EXIT( FILE_DIRSCAN );
        return;
    }

    if ( !d->files )
    {
        PATHNAME f;
        string filespec[ 1 ];
        string filename[ 1 ];
        long handle;
        int ret;
        struct _finddata_t finfo[ 1 ];
        LIST * files = L0;
        int d_length = strlen( d->name );

        memset( (char *)&f, '\0', sizeof( f ) );

        f.f_dir.ptr = d->name;
        f.f_dir.len = d_length;

        /* Now enter contents of directory */

        /* Prepare file search specification for the findfirst() API. */
        if ( d_length == 0 )
            string_copy( filespec, ".\\*" );
        else
        {
            /*
             * We can not simply assume the given folder name will never include
             * its trailing path separator or otherwise we would not support the
             * Windows root folder specified without its drive letter, i.e. '\'.
             */
            char trailingChar = d->name[ d_length - 1 ] ;
            string_copy( filespec, d->name );
            if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
                string_append( filespec, "\\" );
            string_append( filespec, "*" );
        }

        if ( DEBUG_BINDSCAN )
            printf( "scan directory %s\n", dir );

        #if defined(__BORLANDC__) && __BORLANDC__ < 0x550
        if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
        {
            string_free( filespec );
            PROFILE_EXIT( FILE_DIRSCAN );
            return;
        }

        string_new ( filename );
        while ( !ret )
        {
            file_info_t * ff = 0;

            f.f_base.ptr = finfo->ff_name;
            f.f_base.len = strlen( finfo->ff_name );

            string_truncate( filename, 0 );
            path_build( &f, filename );

            files = list_new( files, newstr(filename->value) );
            ff = file_info( filename->value );
            ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
            ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0;
            ff->size = finfo->ff_fsize;
            ff->time = (finfo->ff_ftime << 16) | finfo->ff_ftime;

            ret = findnext( finfo );
        }
        # else
        handle = _findfirst( filespec->value, finfo );

        if ( ret = ( handle < 0L ) )
        {
            string_free( filespec );
            PROFILE_EXIT( FILE_DIRSCAN );
            return;
        }

        string_new( filename );
        while ( !ret )
        {
            file_info_t * ff = 0;

            f.f_base.ptr = finfo->name;
            f.f_base.len = strlen( finfo->name );

            string_truncate( filename, 0 );
            path_build( &f, filename, 0 );

            files = list_new( files, newstr( filename->value ) );
            ff = file_info( filename->value );
            ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
            ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0;
            ff->size = finfo->size;
            ff->time = finfo->time_write;

            ret = _findnext( handle, finfo );
        }

        _findclose( handle );
        # endif
        string_free( filename );
        string_free( filespec );

        d->files = files;
    }

    /* Special case \ or d:\ : enter it */
    {
        unsigned long len = strlen(d->name);
        if ( len == 1 && d->name[0] == '\\' )
            (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
        else if ( len == 3 && d->name[1] == ':' ) {
            (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
            /* We've just entered 3-letter drive name spelling (with trailing
               slash), into the hash table. Now enter two-letter variant,
               without trailing slash, so that if we try to check whether
               "c:" exists, we hit it.

               Jam core has workarounds for that. Given:
                  x = c:\whatever\foo ;
                  p = $(x:D) ;
                  p2 = $(p:D) ;
               There will be no trailing slash in $(p), but there will be one
               in $(p2). But, that seems rather fragile.                
            */
            d->name[2] = 0;
            (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
        }
    }

    /* Now enter contents of directory */
    if ( d->files )
    {
        LIST * files = d->files;
        while ( files )
        {
            file_info_t * ff = file_info( files->string );
            (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
            files = list_next( files );
        }
    }

    PROFILE_EXIT( FILE_DIRSCAN );
}
Beispiel #10
0
int file_is_file( OBJECT * const path )
{
    file_info_t const * const ff = file_query( path );
    return ff ? ff->is_file : -1;
}
Beispiel #11
0
LIST * path_exists( FRAME * frame, int flags )
{
    return file_query( list_front( lol_get( frame->args, 0 ) ) ) ?
        list_new( object_copy( constant_true ) ) : L0;
}
Beispiel #12
0
OBJECT *
search(
    OBJECT * target,
    time_t *time,
    OBJECT * * another_target,
    int file
)
{
    PATHNAME f[1];
    LIST   * varlist;
    string   buf[1];
    int      found = 0;
    /* Will be set to 1 if target location is specified via LOCATE. */
    int      explicitly_located = 0;
    OBJECT * boundname = 0;

    if ( another_target )
        *another_target = 0;

    if (! explicit_bindings )
        explicit_bindings = hashinit( sizeof(BINDING),
                                     "explicitly specified locations");

    string_new( buf );
    /* Parse the filename */

    path_parse( object_str( target ), f );

    f->f_grist.ptr = 0;
    f->f_grist.len = 0;

    varlist = var_get( root_module(), constant_LOCATE );
    if ( !list_empty( varlist ) )
    {
        OBJECT * key;
        f->f_root.ptr = object_str( list_front( varlist ) );
        f->f_root.len = strlen( object_str( list_front( varlist ) ) );

        path_build( f, buf, 1 );

        if ( DEBUG_SEARCH )
            printf( "locate %s: %s\n", object_str( target ), buf->value );

        explicitly_located = 1;

        key = object_new( buf->value );
        timestamp( key, time );
        object_free( key );
        found = 1;
    }
    else if ( varlist = var_get( root_module(), constant_SEARCH ), !list_empty( varlist ) )
    {
        LISTITER iter = list_begin( varlist ), end = list_end( varlist );
        for ( ; iter != end; iter = list_next( iter ) )
        {
            BINDING * ba;
            file_info_t *ff;
            OBJECT * key;
            OBJECT * test_path;

            f->f_root.ptr = object_str( list_item( iter ) );
            f->f_root.len = strlen( object_str( list_item( iter ) ) );

            string_truncate( buf, 0 );
            path_build( f, buf, 1 );

            if ( DEBUG_SEARCH )
                printf( "search %s: %s\n", object_str( target ), buf->value );

            test_path = object_new( buf->value );
            key = path_as_key( test_path );
            object_free( test_path );
            ff = file_query( key );
            timestamp( key, time );

            if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
            {
                if ( DEBUG_SEARCH )
                    printf(" search %s: found explicitly located target %s\n",
                           object_str( target ), object_str( ba->target ) );
                if ( another_target )
                    *another_target = ba->target;
                found = 1;
                object_free( key );
                break;
            }
            else if ( ff && ff->time )
            {
                if ( !file || ff->is_file )
                {
                    found = 1;
                    object_free( key );
                    break;
                }
            }
            object_free( key );
        }
    }

    if ( !found )
    {
        /* Look for the obvious */
        /* This is a questionable move.  Should we look in the */
        /* obvious place if SEARCH is set? */
        OBJECT * key;

        f->f_root.ptr = 0;
        f->f_root.len = 0;

        string_truncate( buf, 0 );
        path_build( f, buf, 1 );

        if ( DEBUG_SEARCH )
            printf( "search %s: %s\n", object_str( target ), buf->value );

        key = object_new( buf->value );
        timestamp( key, time );
        object_free( key );
    }

    boundname = object_new( buf->value );
    string_free( buf );

    if ( explicitly_located )
    {
        int found;
        BINDING * ba;
        OBJECT * key = path_as_key( boundname );
        /* CONSIDER: we probably should issue a warning is another file
           is explicitly bound to the same location. This might break
           compatibility, though. */
        ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
        if ( !found )
        {
            ba->binding = key;
            ba->target = target;
        }
        else
        {
            object_free( key );
        }
    }

    /* prepare a call to BINDRULE if the variable is set */
    call_bind_rule( target, boundname );

    return boundname;
}
Beispiel #13
0
OBJECT * search( OBJECT * target, timestamp * const time,
    OBJECT * * another_target, int const file )
{
    PATHNAME f[ 1 ];
    LIST * varlist;
    string buf[ 1 ];
    int found = 0;
    OBJECT * boundname = 0;

    if ( another_target )
        *another_target = 0;

    if ( !explicit_bindings )
        explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified "
            "locations" );

    string_new( buf );

    /* Parse the filename. */
    path_parse( object_str( target ), f );

    f->f_grist.ptr = 0;
    f->f_grist.len = 0;

    varlist = var_get( root_module(), constant_LOCATE );
    if ( !list_empty( varlist ) )
    {
        OBJECT * key;
        f->f_root.ptr = object_str( list_front( varlist ) );
        f->f_root.len = strlen( object_str( list_front( varlist ) ) );

        path_build( f, buf );

        if ( DEBUG_SEARCH )
            printf( "locate %s: %s\n", object_str( target ), buf->value );

        key = object_new( buf->value );
        timestamp_from_path( time, key );
        object_free( key );
        found = 1;
    }
    else if ( varlist = var_get( root_module(), constant_SEARCH ),
        !list_empty( varlist ) )
    {
        LISTITER iter = list_begin( varlist );
        LISTITER const end = list_end( varlist );
        for ( ; iter != end; iter = list_next( iter ) )
        {
            BINDING * ba;
            file_info_t * ff;
            OBJECT * key;
            OBJECT * test_path;

            f->f_root.ptr = object_str( list_item( iter ) );
            f->f_root.len = strlen( object_str( list_item( iter ) ) );

            string_truncate( buf, 0 );
            path_build( f, buf );

            if ( DEBUG_SEARCH )
                printf( "search %s: %s\n", object_str( target ), buf->value );

            test_path = object_new( buf->value );
            key = path_as_key( test_path );
            object_free( test_path );
            ff = file_query( key );
            timestamp_from_path( time, key );

            if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
            {
                if ( DEBUG_SEARCH )
                    printf(" search %s: found explicitly located target %s\n",
                        object_str( target ), object_str( ba->target ) );
                if ( another_target )
                    *another_target = ba->target;
                found = 1;
                object_free( key );
                break;
            }
            else if ( ff )
            {
                if ( !file || ff->is_file )
                {
                    found = 1;
                    object_free( key );
                    break;
                }
            }
            object_free( key );
        }
    }

    if ( !found )
    {
        /* Look for the obvious. */
        /* This is a questionable move. Should we look in the obvious place if
         * SEARCH is set?
         */
        OBJECT * key;

        f->f_root.ptr = 0;
        f->f_root.len = 0;

        string_truncate( buf, 0 );
        path_build( f, buf );

        if ( DEBUG_SEARCH )
            printf( "search %s: %s\n", object_str( target ), buf->value );

        key = object_new( buf->value );
        timestamp_from_path( time, key );
        object_free( key );
    }

    boundname = object_new( buf->value );
    string_free( buf );

    /* Prepare a call to BINDRULE if the variable is set. */
    call_bind_rule( target, boundname );

    return boundname;
}