OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [io/] [fileio/] [v2_0/] [src/] [file.cxx] - Rev 772

Go to most recent revision | Compare with Previous | Blame | View Log

//==========================================================================
//
//      file.cxx
//
//      Fileio file operations
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos 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 2 or (at your option) any later version.
//
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):           nickg
// Contributors:        nickg
// Date:                2000-05-25
// Purpose:             Fileio file operations
// Description:         These are the functions that operate on files as a whole,
//                      such as open(), creat(), mkdir() etc.
//              
//              
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/io_fileio.h>
#include <pkgconf/isoinfra.h>
 
#include <cyg/infra/cyg_trac.h>        // tracing macros
#include <cyg/infra/cyg_ass.h>         // assertion macros
 
#include <string.h>                    // string functions
#include <dirent.h>
#include <stdio.h>                     // stdin, stdout, stderr
 
#include "fio.h"                       // Private header
 
//==========================================================================
// Implement filesystem locking protocol. 
 
#define LOCK_FS( _mte_ )  {                             \
   CYG_ASSERT(_mte_ != NULL, "Bad mount table entry");  \
   cyg_fs_lock( _mte_, (_mte_)->fs->syncmode);          \
}
 
#define UNLOCK_FS( _mte_ ) cyg_fs_unlock( _mte_, (_mte_)->fs->syncmode)
 
//==========================================================================
// A local strcpy clone that returns a pointer to the end of the copied
// string, not the beginning.
 
static char *my_strcpy( char *s1, const char *s2 )
{
    while( (*s1++ = *s2++) != 0);
    return s1-1;
}
 
//==========================================================================
// Compare a pathname fragment with an element in a pathname. This
// deals with zero or separator termination and avoids substring
// matches.
 
static int pathcmp( const char *path, const char *name )
{
    while( *path == *name && *path != '\0' )
        path++, name++;
    if( *name != '\0' ) return false;
    if( *path == '/' || *path == '\0' ) return true;
    return false;
}
 
//==========================================================================
// CWD support
 
#ifdef CYGPKG_IO_FILEIO_TRACK_CWD
 
// buffer for storing CWD path
static char cwd[PATH_MAX];
static size_t cwd_size = 0;
 
 
static void update_cwd( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
{
    char *p = cwd;
 
    if( mte != cdir_mtab_entry || dir != cdir_dir )
    {
        // Here, the path is relative to the root of the filesystem,
        // or in a totally new filesystem, initialize the cwd with the
        // mount point name of the filesystem.
 
        p = my_strcpy( p, mte->name );
    }
    else p = cwd+cwd_size;
 
    // We must now copy the path into the cwd buffer while dealing
    // with any "." and ".."  components textually.
 
    while( *path != '\0' )
    {
        // skip any stray directory separators.
        if( *path == '/' ) path++;
 
        // Look for a "." entry and just ignore it.
        if( pathcmp( path, "." ) )
        {
            path++;
            continue;
        }
 
        // Look for a ".." entry. If found, chew off the last cwd
        // entry.
        if( pathcmp( path, ".." ) )
        {
            while( *(--p) != '/' );     // back up to last '/'
            path += 2;                  // skip "..".
            continue;
        }
 
        // Otherwise just copy the name fragment over to the cwd.
 
        if( *(p-1) != '/' )
            *p++ = '/';        // add a directory separator
        while( *path != '/' && *path != '\0' )
            *p++ = *path++;
 
    }
 
    // Zero terminate the cwd.
    *p = '\0';
 
    // update size
    cwd_size = p-cwd;
}
 
#else
 
#ifdef CYGPKG_KERNEL
static Cyg_Mutex getcwd_lock CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
#endif
 
#endif
 
 
//==========================================================================
// Open a file
 
__externC int open( const char *path, int oflag, ... )
{
    FILEIO_ENTRY();
 
    // we want to be sure we pull in stdin/out/err, so they can be
    // assigned to fds 0, 1 and 2
#ifdef CYGINT_ISO_STDIO_STREAMS
    CYG_REFERENCE_OBJECT(stdin);
    CYG_REFERENCE_OBJECT(stdout);
    CYG_REFERENCE_OBJECT(stderr);
#endif
 
    CYG_CANCELLATION_POINT;
 
    int ret = 0;
    int fd;
    cyg_file *file;
    cyg_mtab_entry *mte = cdir_mtab_entry;
    cyg_dir dir = cdir_dir;
    const char *name = path;
 
    // At least one of O_RDONLY, O_WRONLY, O_RDWR must be provided
    if( (oflag & O_RDWR) == 0 )
        FILEIO_RETURN(EINVAL);
 
    fd = cyg_fd_alloc(0);
 
    if( fd < 0 )
        FILEIO_RETURN(EMFILE);
 
    file = cyg_file_alloc();
 
    if( file == NULL )
    {
        cyg_fd_free(fd);
        FILEIO_RETURN(ENFILE);
    }
 
    ret = cyg_mtab_lookup( &dir, &name, &mte );
 
    if( 0 != ret )
    {
        cyg_fd_free(fd);
        cyg_file_free(file);
        FILEIO_RETURN(ENOENT);
    }
 
    LOCK_FS( mte );
 
    ret = mte->fs->open( mte, dir, name, oflag, file );
 
    UNLOCK_FS( mte );
 
    if( 0 != ret )
    {
        cyg_fd_free(fd);
        cyg_file_free(file);
        FILEIO_RETURN(ret);
    }
 
    file->f_mte = mte;
    file->f_syncmode = mte->fs->syncmode;
 
    cyg_fd_assign( fd, file );
 
    FILEIO_RETURN_VALUE(fd);
}
 
//==========================================================================
// create a file
 
__externC int creat( const char *path, mode_t mode )
{
    return open( path, O_WRONLY | O_CREAT | O_TRUNC, mode );
}
 
 
//==========================================================================
// Unlink/remove a file
 
__externC int unlink( const char *path )
{
    FILEIO_ENTRY();
 
    int ret = 0;
    cyg_mtab_entry *mte = cdir_mtab_entry;
    cyg_dir dir = cdir_dir;
    const char *name = path;
 
    ret = cyg_mtab_lookup( &dir, &name, &mte );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    LOCK_FS( mte );
 
    ret = mte->fs->unlink( mte, dir, name );
 
    UNLOCK_FS( mte );
 
    FILEIO_RETURN(ret);
}
 
//==========================================================================
// Make a directory
 
__externC int mkdir( const char *path, mode_t mode )
{
    FILEIO_ENTRY();
 
    int ret = 0;
    cyg_mtab_entry *mte = cdir_mtab_entry;
    cyg_dir dir = cdir_dir;
    const char *name = path;
 
    mode=mode;
 
    ret = cyg_mtab_lookup( &dir, &name, &mte );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    LOCK_FS( mte );
 
    ret = mte->fs->mkdir( mte, dir, name );
 
    UNLOCK_FS( mte );
 
    FILEIO_RETURN(ret);
}
 
//==========================================================================
// Remove a directory
 
__externC int rmdir( const char *path )
{
    FILEIO_ENTRY();
 
    int ret = 0;
    cyg_mtab_entry *mte = cdir_mtab_entry;
    cyg_dir dir = cdir_dir;
    const char *name = path;
 
    ret = cyg_mtab_lookup( &dir, &name, &mte );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    LOCK_FS( mte );
 
    ret = mte->fs->rmdir( mte, dir, name );
 
    UNLOCK_FS( mte );
 
    FILEIO_RETURN(ret);
}
 
//==========================================================================
// Rename a file
 
__externC int rename( const char *path1, const char *path2 )
{
    FILEIO_ENTRY();
 
    int ret = 0;
    cyg_mtab_entry *mte1 = cdir_mtab_entry;
    cyg_mtab_entry *mte2 = cdir_mtab_entry;
    cyg_dir dir1 = cdir_dir;
    cyg_dir dir2 = cdir_dir;
    const char *name1 = path1;
    const char *name2 = path2;
 
    ret = cyg_mtab_lookup( &dir1, &name1, &mte1 );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    ret = cyg_mtab_lookup( &dir2, &name2, &mte2 );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    // Cannot rename between different filesystems
    if( mte1 != mte2 )
        FILEIO_RETURN(EXDEV);
 
    LOCK_FS( mte1 );
 
    ret = mte1->fs->rename( mte1, dir1, name1, dir2, name2 );
 
    UNLOCK_FS( mte1 );
 
    FILEIO_RETURN(ret);
}
 
//==========================================================================
// Create a link from an existing file (path1) to a new one (path2)
 
__externC int link( const char *path1, const char *path2 )
{
    FILEIO_ENTRY();
 
    int ret = 0;
    cyg_mtab_entry *mte1 = cdir_mtab_entry;
    cyg_mtab_entry *mte2 = cdir_mtab_entry;
    cyg_dir dir1 = cdir_dir;
    cyg_dir dir2 = cdir_dir;
    const char *name1 = path1;
    const char *name2 = path2;
 
    ret = cyg_mtab_lookup( &dir1, &name1, &mte1 );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    ret = cyg_mtab_lookup( &dir2, &name2, &mte2 );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    // Cannot hard-link between different filesystems
    if( mte1 != mte2 )
        FILEIO_RETURN(EXDEV);
 
    LOCK_FS( mte1 );
 
    ret = mte1->fs->link( mte1, dir1, name1, dir2, name2, CYG_FSLINK_HARD );
 
    UNLOCK_FS( mte1 );
 
    FILEIO_RETURN(ret);
}
 
//==========================================================================
// Change current directory
 
__externC int chdir( const char *path )
{
    FILEIO_ENTRY();
 
    int ret = 0;
    cyg_mtab_entry *mte = cdir_mtab_entry;
    cyg_dir dir = cdir_dir;
    cyg_dir newdir;
    const char *name = path;
 
    ret = cyg_mtab_lookup( &dir, &name, &mte );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    LOCK_FS(mte);
 
    ret = mte->fs->chdir( mte, dir, name, &newdir );
 
    UNLOCK_FS(mte);
 
    if( 0 != ret )
        FILEIO_RETURN(ret);
 
#ifdef CYGPKG_IO_FILEIO_TRACK_CWD
    update_cwd( mte, dir, name );
#endif
 
    if( cdir_mtab_entry != NULL && cdir_dir != CYG_DIR_NULL )
    {
        // Now detach from current cdir. We call the current directory's
        // chdir routine with a NULL dir_out pointer.
 
        LOCK_FS(cdir_mtab_entry);
 
        ret = cdir_mtab_entry->fs->chdir( cdir_mtab_entry, cdir_dir, NULL, NULL );
 
        UNLOCK_FS(cdir_mtab_entry);
 
        // We really shouldn't get an error here.
        if( 0 != ret )
            FILEIO_RETURN(ret);
    }
 
    cdir_mtab_entry = mte;
    cdir_dir = newdir;
 
    FILEIO_RETURN(ENOERR);
}
 
//==========================================================================
// Get file statistics
 
__externC int stat( const char *path, struct stat *buf )
{
    FILEIO_ENTRY();
 
    int ret = 0;
    cyg_mtab_entry *mte = cdir_mtab_entry;
    cyg_dir dir = cdir_dir;
    const char *name = path;
 
    ret = cyg_mtab_lookup( &dir, &name, &mte );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    LOCK_FS( mte );
 
    ret = mte->fs->stat( mte, dir, name, buf );
 
    UNLOCK_FS( mte );
 
    FILEIO_RETURN(ret);
}
 
//==========================================================================
// Get file configurable pathname variables
 
__externC long pathconf( const char *path, int vname )
{
    FILEIO_ENTRY();
 
    int ret = 0;
    cyg_mtab_entry *mte = cdir_mtab_entry;
    cyg_dir dir = cdir_dir;
    const char *name = path;
 
    ret = cyg_mtab_lookup( &dir, &name, &mte );
 
    if( 0 != ret )
        FILEIO_RETURN(ENOENT);
 
    struct cyg_pathconf_info info;
 
    info.name = vname;
    info.value = 0;
 
    LOCK_FS( mte );
 
    ret = mte->fs->getinfo( mte, dir, name,
                            FS_INFO_CONF, (char *)&info, sizeof(info) );
 
    UNLOCK_FS( mte );
 
    if( 0 != ret )
        FILEIO_RETURN(ret);
 
    FILEIO_RETURN_VALUE(info.value);
}
 
//==========================================================================
// Access() function.
// This simply piggybacks onto stat().
 
extern int 	access(const char *path, int amode)
{
    FILEIO_ENTRY();
 
    int ret;
    struct stat buf;
 
    ret = stat( path, &buf );
 
    // Translate not found into EACCES if the F_OK bit is
    // set.
    if( (amode & F_OK) && (ret < 0) && (errno == ENOENT) )
        FILEIO_RETURN(EACCES);
 
    // All other errors go straight back to the user.
    if( ret < 0 )
        FILEIO_RETURN_VALUE(ret);
 
    // At present we do not have any access modes, so there is nothing
    // to test.  Just return success for all access modes.
 
    FILEIO_RETURN(ENOERR);
}
 
//==========================================================================
// getcwd()
 
__externC char *getcwd( char *buf, size_t size )
{
    FILEIO_ENTRY();
 
    int err = ENOERR;
    cyg_mtab_entry *mte = cdir_mtab_entry;
    cyg_dir dir = cdir_dir;
    cyg_getcwd_info info;
 
    if( size == 0 )
    {
        errno = EINVAL;
        FILEIO_RETURN_VALUE(NULL);        
    }
 
    info.buf = buf;
    info.size = size;
 
    LOCK_FS( mte );
 
    err = mte->fs->getinfo( mte, dir, "",
                            FS_INFO_GETCWD, (char *)&info, sizeof(info) );
 
    UNLOCK_FS( mte );
 
    if( err == ENOERR )
        FILEIO_RETURN_VALUE(buf);
 
    // Attempting to use filesystem support for getcwd() has
    // failed.
 
#ifdef CYGPKG_IO_FILEIO_TRACK_CWD
 
    // If this option is set, the current directory path has been
    // tracked in chdir(). Just report that value here.
 
    if( size < cwd_size+1 )
    {
        errno = ERANGE;
        FILEIO_RETURN_VALUE(NULL);        
    }
 
    char *p = my_strcpy( buf, cwd );
    *p = '\0';
 
#else
 
    // As a fallback we try to use ".." entries in the directory tree
    // to climb back up to the root.  Because we cannot assume that
    // any filesystem can handle more than one directory pointer we
    // have to do the climbing textually, by manufacturing a path name
    // consisting of ".."s. At each level we then scan the parent
    // directory looking for the entry for the lower level directory
    // by matching st_ino values. This is not guaranteed to work at
    // all since there is no requirement on filesystems to support "."
    // and "..", or for them to report distinct inode values in
    // stat().
 
    static char ddbuf[PATH_MAX];
    char *p = buf+size-1;
    int ddbufpos;
 
    // Claim lock to serialize use of ddbuf.
    FILEIO_MUTEX_LOCK(getcwd_lock);
 
    // Initialize ddbuf with ".".
    ddbuf[0] = '.';
    ddbuf[1] = '\0';
    ddbufpos = 1;
 
    // Start result buffer with a zero terminator. We accumulate the
    // path name in the top end of the result buffer.
    *p = '\0';
 
    for(;;)
    {
        struct stat sdbuf;
        struct stat sddbuf;
 
        // Get status for "." and "..". If the filesystem does not
        // support these, then this whole function will fail here.
 
        err = stat( ddbuf, &sdbuf );
        if( err < 0 ) break;
 
        ddbuf[ddbufpos++] = '/';
        ddbuf[ddbufpos++] = '.';
        ddbuf[ddbufpos++] = '.';
        ddbuf[ddbufpos] = '\0';
 
        err = stat( ddbuf, &sddbuf );
        if( err < 0 ) break;
 
        // See whether we are at the root. This will be true when
        // the inode numbers of "." and ".." are the same.
        if( sdbuf.st_ino == sddbuf.st_ino )
            break;
 
        // We now need to find an entry in the ".." directory that
        // matches the inode number of ".".
 
        struct dirent de;
        DIR *d = opendir( ddbuf );
        if( d == NULL )
        {
            err = -1;
            break;
        }
 
        for(;;)
        {
            struct dirent *res;
            struct stat objstat;
            int i;
 
            err = readdir_r( d, &de, &res );
            if( err < 0 || res == NULL ) break;
 
            // Skip "." and ".." entries.
            if( pathcmp( de.d_name, "." ) || pathcmp( de.d_name, ".." ) )
                continue;
 
            // Tack the name of the directory entry on to the ddbuf
            // and stat the object.
 
            ddbuf[ddbufpos] = '/';
            for( i = 0; de.d_name[i] != '\0'; i++ )
                ddbuf[ddbufpos+i+1] = de.d_name[i];
            ddbuf[ddbufpos+i+1] = '\0';
 
            // Take a look at it
            err = stat( ddbuf, &objstat );
            if( err < 0 ) break;
 
            // Cast out directories
            if( !S_ISDIR(objstat.st_mode) )
                continue;
 
            // We have a directory. Compare its inode with that of "."
            // and if they are the same, we have found our entry.
 
            if( sdbuf.st_ino == objstat.st_ino )
                break;
        }
 
        ddbuf[ddbufpos] = '\0'; // reterminate ddbuf
 
        closedir( d );
 
        // Halt on any errors.
        if( err < 0 )
            break;
 
        // Here de contains the name of the directory entry in ".."
        // that has the same inode as ".". Add the name to the path we
        // are accumulating in the buffer.
 
        char *q = de.d_name;
        while( *q != '\0' ) q++;        // skip to end of name
 
        do
        {
            *--p = *--q;
        } while( q != de.d_name );
 
        *--p = '/';                     // add a separator
    }
 
    // We have finished using ddbuf now.
    FILEIO_MUTEX_UNLOCK(getcwd_lock);
 
    if( err < 0 )
        FILEIO_RETURN_VALUE(NULL);
 
    // We have the directory path in the top end of the buffer.  Add
    // the mount point name at the beginning and copy the rest of the
    // name down.
 
    char *bp = buf;
 
    bp = my_strcpy( bp, mte->name );
 
    // Sort out the separators between the mount name and the
    // pathname.  This is a bit messy since we have to deal with mount
    // names of both "/" and "/foo" and pathnames that start with '/'
    // or are empty.
    if( *(bp-1) != '/' && *p != '\0' ) *bp++ = '/';
    if( *p == '/' ) p++;
 
    // Now copy the path over.
    while( *p )
        *bp++ = *p++;
 
    *bp = '\0';                         // Terminate the string
 
    // All done!
 
#endif
 
    FILEIO_RETURN_VALUE(buf);
}
 
// -------------------------------------------------------------------------
// EOF file.cxx
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.