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

Subversion Repositories openrisc_me

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/rtos/ecos-2.0/packages/io/fileio
    from Rev 27 to Rev 174
    Reverse comparison

Rev 27 → Rev 174

/v2_0/cdl/fileio.cdl
0,0 → 1,243
# ====================================================================
#
# fileio.cdl
#
# FILEIO layer configuration data
#
# ====================================================================
#####ECOSGPLCOPYRIGHTBEGIN####
## -------------------------------------------
## This file is part of eCos, the Embedded Configurable Operating System.
## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
## Copyright (C) 2002 Nick Garnett
##
## 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:
# Date: 2000-5-25
#
#####DESCRIPTIONEND####
#
# ====================================================================
 
cdl_package CYGPKG_IO_FILEIO {
display "POSIX File IO compatibility layer"
description "This package enables the POSIX compatibility
layer that implements IEEE 1003.1 file IO."
include_dir cyg/fileio
doc ref/fileio.html
requires CYGPKG_ISOINFRA
requires CYGPKG_ERROR
requires CYGINT_ISO_ERRNO
requires CYGINT_ISO_ERRNO_CODES
requires CYGINT_ISO_STRING_STRFUNCS
 
implements CYGINT_ISO_FCNTL
implements CYGINT_ISO_OPEN
implements CYGINT_ISO_DIRENT
 
requires { CYGBLD_ISO_DIRENT_HEADER == "<cyg/fileio/dirent.h>" }
requires { CYGBLD_ISO_OPEN_MAX_HEADER == "<cyg/fileio/limits.h>" }
requires { CYGBLD_ISO_NAME_MAX_HEADER == "<cyg/fileio/limits.h>" }
 
compile fd.cxx file.cxx io.cxx dir.cxx
compile -library=libextras.a misc.cxx
 
cdl_interface CYGINT_IO_FILEIO_FS {
display "Filesystems interfacing to FILEIO"
no_define
description "
Each filesystem driver which FILEIO can use implements
this interface. You can use this to determine if there are
any filesystems configured in the system."
}
 
cdl_option CYGFUN_IO_FILEIO_SELECT {
display "Enable support for select()"
active_if CYGPKG_KERNEL
implements CYGINT_ISO_SELECT
default_value 1
description "
This option enables support for select()."
 
compile select.cxx
}
 
cdl_option CYGPKG_IO_FILEIO_DEVFS_SUPPORT {
display "Enable devfs support"
active_if CYGPKG_IO
default_value { CYGPKG_REDBOOT ? 0 : 1 }
description "
This option enables support for the devfs file system."
 
compile -library=libextras.a devfs.cxx
}
 
cdl_option CYGPKG_IO_FILEIO_SOCKET_SUPPORT {
display "Enable socket support"
active_if CYGPKG_NET
active_if CYGPKG_KERNEL
default_value 1
description "
This option enables support for the socket interface. It is
only present if the NET package is included."
 
compile socket.cxx
}
cdl_option CYGNUM_FILEIO_NFILE {
display "Maximum number of open files"
flavor data
default_value 16
legal_values 1 to 9999999
description "This option controls the number of open files
that are allowed for all filesystems."
}
 
cdl_option CYGNUM_FILEIO_NFD {
display "Maximum number of open file descriptors"
flavor data
default_value 16
legal_values CYGNUM_FILEIO_NFILE to 9999999
description "This option controls the number of open file descriptors
that are allowed for all filesystems."
}
 
cdl_option CYGNUM_FILEIO_FSTAB_MAX {
display "Maximum number of installed filesystems"
flavor data
default_value 4
legal_values 1 to 9999999
description "This option controls the maximum number of filesystems
that can be handled by the fileio system."
 
}
 
cdl_option CYGNUM_FILEIO_MTAB_MAX {
display "Maximum number of mounted filesystems"
flavor data
default_value 8
legal_values CYGNUM_FILEIO_MTAB_EXTRA to 9999999
description "This option controls the maximum number of mounted
filesystems that can be handled by the fileio system."
 
}
 
cdl_option CYGNUM_FILEIO_MTAB_EXTRA {
display "Number of dynamically mounted filesystems"
flavor data
default_value 8
legal_values 0 to 9999999
description "This option controls the number of mounted
filesystems that can be created dynamically."
}
 
cdl_option CYGNUM_FILEIO_NSTAB_MAX {
display "Maximum number of installed network stacks"
flavor data
default_value 1
legal_values 1 to 9999999
description "This option controls the maximum number of installed
network stacks that can be handled by the fileio system."
}
 
cdl_option CYGPKG_IO_FILEIO_TRACK_CWD {
display "Enable current directory tracking"
flavor bool
default_value 1
description "This option enables tracking of the name of the current
directory in the FILEIO package, to support the getcwd()
function. When this option is enabled the FILEIO package
will attempt to maintain a string that names the current
directory. It does this textually, dealing with \".\" and
\"..\" entries by textual manipulation. While this should
always provide a path for the current directory, it may not
be the best, if symbolic links are present. This tracked CWD
is only used if a filesystem does not support the
FS_INFO_GETCWD key. "
}
 
cdl_component CYGPKG_IO_FILEIO_INODE {
display "Generic inode support"
flavor bool
description "This option enables generic inode support useful to
some filesystems. Not all filesystems require this
so it is not enabled by default."
default_value 0
requires CYGINT_ISO_MALLOC
compile inocache.cxx
 
cdl_option CYGNUM_IO_FILEIO_MAX_INODE_CACHE_DEAD {
display "Maximum space for unused cached inodes"
flavor data
default_value 10
description "The inode cache allows a maximum limit to be set
for the number of unused inodes still in the
cache before they are freed. It may be set to 0
to indicate no dead inode caching should be
provided."
}
}
 
cdl_option CYGNUM_FILEIO_IOVEC_MAX {
display "Maximum size of iovec used by readv/writev"
flavor data
default_value 16
legal_values 1 to 9999999
description "This option controls the maximum size of the iovec
structure that can be used by readv()/writev(). This
limit is required because the iovec structure must be
invariant (to the user), thus a copy needs to be made
by the interface routines. The limit is merely a
control over the amount of stack space used by the
readv()/writev() functions."
 
}
 
# ----------------------------------------------------------------
# Tests
 
cdl_option CYGPKG_IO_FILEIO_TESTS {
display "Fileio tests"
flavor data
no_define
calculated { "tests/fileio1 tests/socket tests/select tests/stdio tests/pselect" }
description "
This option specifies the set of tests for the FileIO package."
}
}
 
# ====================================================================
# End of fileio.cdl
 
 
/v2_0/tests/select.c
0,0 → 1,637
//==========================================================================
//
// select.c
//
// Test select implementation
//
//==========================================================================
//####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: Test select implementation
// Description:
//
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/system.h>
#include <pkgconf/isoinfra.h>
 
#ifndef CYGINT_ISO_PTHREAD_IMPL
# define NA_MSG "POSIX threads needed to run test"
#endif
 
#include <cyg/infra/testcase.h>
 
#ifndef NA_MSG
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#ifdef CYGPKG_IO_SERIAL
#include <pkgconf/io_serial.h>
#endif
 
#define __ECOS 1 // dont like this at all
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
 
#ifdef CYGPKG_NET
#include <network.h>
#include <arpa/inet.h>
#define TEST_NET
#endif
 
#ifdef CYGPKG_IO_SERIAL_LOOP
#define TEST_DEV
#endif
 
#include <pthread.h>
#include <signal.h>
 
 
#include <cyg/infra/diag.h> // HAL polled output
 
//--------------------------------------------------------------------------
 
#define SHOW_RESULT( _fn, _res ) \
diag_printf("INFO: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
 
//--------------------------------------------------------------------------
// Thread stack.
 
char thread1_stack[PTHREAD_STACK_MIN*2];
char thread2_stack[PTHREAD_STACK_MIN*2];
 
//--------------------------------------------------------------------------
// Local variables
 
// Thread IDs
pthread_t thread1;
pthread_t thread2;
 
#ifdef TEST_NET
struct sockaddr_in sa;
#endif
 
//--------------------------------------------------------------------------
// Test buffers
// The buffer size here must be less that the size of the serial device
// buffers since the serial devices do not currently implement flow
// control.
 
#define TEST_BUFSIZE 100
 
#ifdef TEST_NET
static char buf1[TEST_BUFSIZE];
static char buf2[TEST_BUFSIZE];
static char buf3[TEST_BUFSIZE];
#endif
#ifdef TEST_DEV
static char sbuf1[TEST_BUFSIZE];
static char sbuf2[TEST_BUFSIZE];
static char sbuf3[TEST_BUFSIZE];
#endif
 
 
//--------------------------------------------------------------------------
 
void show_fdsets( char *s, int nfd, fd_set *rd, fd_set *wr, fd_set *ex )
{
int i;
diag_printf("INFO:<%s nfd %d ",s,nfd);
 
if( rd )
{
diag_printf("rd: [");
for( i = 0; i < nfd ; i++ )
if( FD_ISSET( i, rd ) ) diag_printf("%d ",i);
diag_printf("] ");
}
if( wr )
{
diag_printf("wr: [");
for( i = 0; i < nfd ; i++ )
if( FD_ISSET( i, wr ) ) diag_printf("%d ",i);
diag_printf("] ");
}
if( ex )
{
diag_printf("ex: [");
for( i = 0; i < nfd ; i++ )
if( FD_ISSET( i, ex ) ) diag_printf("%d ",i);
diag_printf("] ");
}
 
diag_printf(">\n");
}
 
 
//--------------------------------------------------------------------------
 
void *pthread_entry1( void *arg)
{
#ifdef TEST_NET
int fd = 0, fd2 = -1;
struct sockaddr_in accsa;
socklen_t accsa_len = sizeof(accsa);
int netstate = 0;
#endif
#ifdef TEST_DEV
int ser0;
int serstate = 0;
#endif
#if defined(TEST_DEV) || defined(TEST_NET)
int i;
ssize_t done;
#endif
int netdone = 0;
int serdone = 0;
int err;
fd_set rd, wr;
CYG_TEST_INFO( "Thread 1 running" );
 
FD_ZERO( &rd );
FD_ZERO( &wr );
#ifdef TEST_DEV
 
CYG_TEST_INFO( "Thread1: calling open()");
ser0 = open("/dev/ser0", O_RDWR );
if( ser0 < 0 ) SHOW_RESULT( open, ser0 );
CYG_TEST_CHECK( ser0 >= 0, "open(/dev/ser0) returned error");
 
FD_SET( ser0, &rd );
#else
serdone = 1;
#endif
 
#ifdef TEST_NET
 
for( i = 0; i < TEST_BUFSIZE; i++ ) buf1[i] = i;
CYG_TEST_INFO( "Thread1: calling socket()");
fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( fd < 0 ) SHOW_RESULT( socket, fd );
CYG_TEST_CHECK( fd >= 0, "socket() returned error");
 
CYG_TEST_INFO( "Thread1: calling bind()");
err = bind( fd, (struct sockaddr *)&sa, sizeof(sa));
if( err < 0 ) SHOW_RESULT( bind, err );
CYG_TEST_CHECK( err == 0, "bind() returned error");
 
CYG_TEST_INFO( "Thread1: calling listen()");
err = listen( fd, 3);
if( err < 0 ) SHOW_RESULT( listen, err );
CYG_TEST_CHECK( err == 0, "listen() returned error");
 
FD_SET( fd, &rd );
#else
netdone = 1;
#endif
 
while(!(netdone && serdone))
{
fd_set rd_res = rd;
fd_set wr_res = wr;
CYG_TEST_INFO( "Thread1: calling select()");
show_fdsets( "Thread1 request: ", 8, &rd_res, &wr_res, NULL );
err = select( 8, &rd_res, &wr_res, NULL, NULL );
if( err < 0 ) SHOW_RESULT( select, err );
CYG_TEST_CHECK( err >= 0, "select() returned error");
show_fdsets( "Thread1 result: ", 8, &rd_res, &wr_res, NULL );
#ifdef TEST_NET
switch( netstate )
{
case 0:
CYG_TEST_INFO( "Thread1: netstate 0");
if( FD_ISSET( fd, &rd_res ) )
{
CYG_TEST_INFO( "Thread1: calling accept(fd)");
fd2 = accept( fd, (struct sockaddr *)&accsa, &accsa_len );
if( fd2 < 0 ) SHOW_RESULT( accept, fd2 );
CYG_TEST_CHECK( fd2 >= 0, "accept() returned error");
 
FD_CLR( fd, &rd );
FD_SET( fd2, &wr );
 
netstate++;
}
break;
 
 
case 1:
CYG_TEST_INFO( "Thread1: netstate 1");
if( FD_ISSET( fd2, &wr_res ) )
{
CYG_TEST_INFO( "Thread1: calling write(fd2)");
done = write( fd2, buf1, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( write, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "write() returned bad size");
 
FD_CLR( fd2, &wr );
FD_SET( fd2, &rd );
 
netstate++;
}
break;
 
case 2:
CYG_TEST_INFO( "Thread1: netstate 2");
if( FD_ISSET( fd2, &rd_res ) )
{
CYG_TEST_INFO( "Thread1: calling read(fd2)");
done = read( fd2, buf3, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( read, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "read() returned bad size");
 
for( i = 0; i < TEST_BUFSIZE; i++ )
if( buf1[i] != buf3[i] )
diag_printf("buf1[%d](%02x) != buf3[%d](%02x)\n",i,buf1[i],i,buf3[i]);
 
FD_CLR( fd2, &rd );
 
netstate++;
netdone = 1;
CYG_TEST_INFO( "Thread1: netdone");
}
break;
}
#endif
 
#ifdef TEST_DEV
switch( serstate )
{
case 0:
CYG_TEST_INFO( "Thread1: serstate 0");
if( FD_ISSET( ser0, &rd_res ) )
{
CYG_TEST_INFO( "Thread1: calling read(ser0)");
done = read( ser0, sbuf2, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( read, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "read() returned bad size");
 
for( i = 0; i < TEST_BUFSIZE; i++ )
if( sbuf1[i] != sbuf2[i] )
diag_printf("buf1[%d](%02x) != buf2[%d](%02x)\n",i,sbuf1[i],i,sbuf2[i]);
 
FD_CLR( ser0, &rd );
FD_SET( ser0, &wr );
serstate++;
}
break;
case 1:
CYG_TEST_INFO( "Thread1: serstate 1");
if( FD_ISSET( ser0, &wr_res ) )
{
CYG_TEST_INFO( "Thread1: calling write(ser0)");
done = write( ser0, sbuf2, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( write, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "write() returned bad size");
 
FD_CLR( ser0, &wr );
serstate++;
serdone = 1;
CYG_TEST_INFO( "Thread1: serdone");
}
else FD_SET( ser0, &wr );
break;
}
#endif
}
 
#ifdef TEST_NET
CYG_TEST_INFO( "Thread1: calling close(fd)");
err = close(fd);
if( err < 0 ) SHOW_RESULT( close, err );
CYG_TEST_CHECK( err == 0, "close() returned error");
 
if( fd2 >= 0 )
{
CYG_TEST_INFO( "Thread1: calling close(fd2)");
err = close(fd2);
if( err < 0 ) SHOW_RESULT( close, err );
CYG_TEST_CHECK( err == 0, "close() returned error");
}
#endif
#ifdef TEST_DEV
CYG_TEST_INFO( "Thread1: calling close(ser0)");
err = close(ser0);
if( err < 0 ) SHOW_RESULT( close, err );
CYG_TEST_CHECK( err == 0, "close() returned error");
#endif
CYG_TEST_INFO( "Thread1: calling pthread_exit()");
pthread_exit( arg );
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry2( void *arg)
{
#ifdef TEST_NET
int fd;
int netstate = 0;
#endif
#ifdef TEST_DEV
int ser1;
int serstate = 0;
#endif
#if defined(TEST_DEV) || defined(TEST_NET)
int i;
ssize_t done;
#endif
int netdone = 0;
int serdone = 0;
int err;
fd_set rd, wr;
CYG_TEST_INFO( "Thread 2 running" );
 
FD_ZERO( &rd );
FD_ZERO( &wr );
 
#ifdef TEST_NET
CYG_TEST_INFO( "Thread2: calling socket()");
fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( fd < 0 ) SHOW_RESULT( socket, fd );
CYG_TEST_CHECK( fd >= 0, "socket() returned error");
 
CYG_TEST_INFO( "Thread2: calling connect()");
err = connect( fd, (struct sockaddr *)&sa, sizeof(sa));
if( err < 0 ) SHOW_RESULT( connect, err );
CYG_TEST_CHECK( err == 0, "connect() returned error");
 
FD_SET( fd, &rd );
#else
netdone = 1;
#endif
 
#ifdef TEST_DEV
for( i = 0; i < TEST_BUFSIZE; i++ ) sbuf1[i] = i;
CYG_TEST_INFO( "Thread2: calling open(/dev/ser1)");
ser1 = open("/dev/ser1", O_RDWR );
if( ser1 < 0 ) SHOW_RESULT( open, ser1 );
CYG_TEST_CHECK( ser1 >= 0, "open(/dev/ser1) returned error");
 
CYG_TEST_INFO( "Thread2: calling write(ser1)");
done = write( ser1, sbuf1, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( write, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "write() returned bad size");
FD_SET( ser1, &wr );
#else
serdone = 1;
#endif
while(!(netdone && serdone))
{
fd_set rd_res = rd;
fd_set wr_res = wr;
CYG_TEST_INFO( "Thread2: calling select()");
show_fdsets( "Thread2 request: ", 8, &rd_res, &wr_res, NULL );
err = select( 8, &rd_res, &wr_res, NULL, NULL );
if( err < 0 ) SHOW_RESULT( select, err );
CYG_TEST_CHECK( err >= 0, "select() returned error");
show_fdsets( "Thread2 result: ", 8, &rd_res, &wr_res, NULL );
#ifdef TEST_NET
switch( netstate )
{
case 0:
CYG_TEST_INFO( "Thread2: netstate 0");
if( FD_ISSET( fd, &rd_res ) )
{
CYG_TEST_INFO( "Thread2: calling read()");
done = read( fd, buf2, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( read, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "read() returned bad size");
 
for( i = 0; i < TEST_BUFSIZE; i++ )
if( buf1[i] != buf2[i] )
diag_printf("buf1[%d](%02x) != buf2[%d](%02x)\n",i,buf1[i],i,buf2[i]);
 
netstate++;
 
FD_CLR( fd, &rd );
FD_SET( fd, &wr );
}
break;
 
case 1:
CYG_TEST_INFO( "Thread2: netstate 1");
if( FD_ISSET( fd, &wr_res ) )
{
 
CYG_TEST_INFO( "Thread2: calling write()");
done = write( fd, buf2, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( write, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "write() returned bad size");
 
FD_CLR( fd, &wr );
netstate++;
netdone = 1;
CYG_TEST_INFO( "Thread2: netdone");
}
break;
}
#endif
 
#ifdef TEST_DEV
switch( serstate )
{
case 0:
CYG_TEST_INFO( "Thread2: serstate 0");
if( FD_ISSET( ser1, &wr_res ) )
{
FD_CLR( ser1, &wr );
FD_SET( ser1, &rd );
serstate++;
}
break;
 
case 1:
CYG_TEST_INFO( "Thread2: serstate 1");
if( FD_ISSET( ser1, &rd_res ) )
{
CYG_TEST_INFO( "Thread2: calling read(ser1)");
done = read( ser1, sbuf3, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( read, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "read() returned bad size");
 
for( i = 0; i < TEST_BUFSIZE; i++ )
if( sbuf1[i] != sbuf3[i] )
diag_printf("sbuf1[%d](%02x) != sbuf3[%d](%02x)\n",i,sbuf1[i],i,sbuf3[i]);
 
FD_CLR( ser1, &rd );
 
serstate++;
serdone = 1;
CYG_TEST_INFO( "Thread2: serdone");
}
break;
}
#endif
}
 
#ifdef TEST_NET
CYG_TEST_INFO( "Thread2: calling close(fd)");
err = close(fd);
if( err < 0 ) SHOW_RESULT( close, err );
CYG_TEST_CHECK( err == 0, "close() returned error");
#endif
#ifdef TEST_DEV
CYG_TEST_INFO( "Thread2: calling close(ser1)");
err = close(ser1);
if( err < 0 ) SHOW_RESULT( close, err );
CYG_TEST_CHECK( err == 0, "close(ser1) returned error");
#endif
CYG_TEST_INFO( "Thread2: calling pthread_exit()");
pthread_exit( arg );
}
 
//==========================================================================
// main
 
int main( int argc, char **argv )
{
void *retval;
pthread_attr_t attr;
struct sched_param schedparam;
 
CYG_TEST_INIT();
 
#ifdef TEST_NET
sa.sin_family = AF_INET;
sa.sin_len = sizeof(sa);
inet_aton("127.0.0.1", &sa.sin_addr);
sa.sin_port = htons(1234);
init_all_network_interfaces();
#endif
// Create test threads
 
{
pthread_attr_init( &attr );
 
schedparam.sched_priority = 10;
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
pthread_attr_setschedparam( &attr, &schedparam );
pthread_attr_setstackaddr( &attr, (void *)&thread1_stack[sizeof(thread1_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread1_stack) );
 
pthread_create( &thread1,
&attr,
pthread_entry1,
(void *)0x12345671);
}
 
{
pthread_attr_init( &attr );
 
schedparam.sched_priority = 5;
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
pthread_attr_setschedparam( &attr, &schedparam );
pthread_attr_setstackaddr( &attr, (void *)&thread2_stack[sizeof(thread2_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread2_stack) );
 
pthread_create( &thread2,
&attr,
pthread_entry2,
(void *)0x12345672);
}
// Now join with thread1
CYG_TEST_INFO( "Main: calling pthread_join(thread1)");
pthread_join( thread1, &retval );
 
// And thread 2
CYG_TEST_INFO( "Main: calling pthread_join(thread2)");
pthread_join( thread2, &retval );
 
CYG_TEST_PASS_FINISH("select");
}
 
#else
 
//==========================================================================
// main
 
void cyg_start(void)
{
CYG_TEST_INIT();
 
CYG_TEST_NA(NA_MSG);
}
 
#endif
 
 
// -------------------------------------------------------------------------
// EOF socket.c
/v2_0/tests/pselect.c
0,0 → 1,361
//==========================================================================
//
// pselect.c
//
// Test pselect implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Nick Garnett
//
// 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: 2002-11-08
// Purpose: Test pselect implementation
// Description:
//
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/system.h>
#include <pkgconf/isoinfra.h>
 
#ifndef CYGINT_ISO_PTHREAD_IMPL
# define NA_MSG "POSIX threads needed to run test"
#elif !defined CYGPKG_NET
# define NA_MSG "NET package needed to run test"
#endif
 
#include <cyg/infra/testcase.h>
 
#ifndef NA_MSG
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#define __ECOS 1 // dont like this at all
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
 
#include <network.h>
#include <arpa/inet.h>
 
#include <pthread.h>
#include <signal.h>
 
#include <sys/select.h>
 
 
#include <cyg/infra/diag.h> // HAL polled output
 
//--------------------------------------------------------------------------
 
#define SHOW_RESULT( _fn, _res ) \
diag_printf("INFO: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
 
//--------------------------------------------------------------------------
// Thread stacks
 
char thread1_stack[PTHREAD_STACK_MIN*2];
char thread2_stack[PTHREAD_STACK_MIN*2];
 
//--------------------------------------------------------------------------
// Local variables
 
// Thread IDs
pthread_t thread1;
pthread_t thread2;
 
struct sockaddr_in sa;
 
volatile int sigusr1_calls = 0;
volatile int sigusr1_sent = 0;
volatile int pselect_wakeups = 0;
volatile int pselect_eintr = 0;
 
volatile cyg_bool running = true;
 
//--------------------------------------------------------------------------
 
void show_fdsets( char *s, int nfd, fd_set *rd, fd_set *wr, fd_set *ex )
{
int i;
diag_printf("INFO:<%s nfd %d ",s,nfd);
 
if( rd )
{
diag_printf("rd: [");
for( i = 0; i < nfd ; i++ )
if( FD_ISSET( i, rd ) ) diag_printf("%d ",i);
diag_printf("] ");
}
if( wr )
{
diag_printf("wr: [");
for( i = 0; i < nfd ; i++ )
if( FD_ISSET( i, wr ) ) diag_printf("%d ",i);
diag_printf("] ");
}
if( ex )
{
diag_printf("ex: [");
for( i = 0; i < nfd ; i++ )
if( FD_ISSET( i, ex ) ) diag_printf("%d ",i);
diag_printf("] ");
}
 
diag_printf(">\n");
}
 
//--------------------------------------------------------------------------
 
void sigusr1( int sig, siginfo_t *info, void *context )
{
CYG_TEST_CHECK( pthread_self() == thread1, "Sigusr1: not called by thread 1\n");
sigusr1_calls++;
}
 
//--------------------------------------------------------------------------
// Selecting thread
 
// This thread just opens up a socket ready to accept a connection and
// then calls pselect() to wait for it. The timeout is set to 0 so we
// actually just poll.
 
void *pthread_entry1( void *arg)
{
int fd = 0;
int err;
fd_set rd, wr;
sigset_t mask, oldmask;
struct sigaction sigact;
struct timespec ts;
CYG_TEST_INFO( "Thread 1 running" );
 
FD_ZERO( &rd );
FD_ZERO( &wr );
 
sigfillset( &mask );
pthread_sigmask( SIG_SETMASK, &mask, &oldmask );
sigdelset( &mask, SIGUSR1 );
 
sigact.sa_mask = mask;
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = sigusr1;
 
err = sigaction( SIGUSR1, &sigact, NULL );
if( err < 0 ) SHOW_RESULT( sigact, err );
 
CYG_TEST_INFO( "Thread1: calling socket()");
fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( fd < 0 ) SHOW_RESULT( socket, fd );
CYG_TEST_CHECK( fd >= 0, "socket() returned error");
 
CYG_TEST_INFO( "Thread1: calling bind()");
err = bind( fd, (struct sockaddr *)&sa, sizeof(sa));
if( err < 0 ) SHOW_RESULT( bind, err );
CYG_TEST_CHECK( err == 0, "bind() returned error");
 
CYG_TEST_INFO( "Thread1: calling listen()");
err = listen( fd, 3);
if( err < 0 ) SHOW_RESULT( listen, err );
CYG_TEST_CHECK( err == 0, "listen() returned error");
 
FD_SET( fd, &rd );
 
ts.tv_sec = 0;
ts.tv_nsec = 0;
while( running )
{
fd_set rd_res = rd;
fd_set wr_res = wr;
 
// ts.tv_nsec = 1000000 * (pselect_wakeups % 10);
err = pselect( 8, &rd_res, &wr_res, NULL, &ts, &mask );
if( err < 0 )
{
if( errno == EINTR ) pselect_eintr++;
else SHOW_RESULT( pselect, err );
}
if( err > 0 ) show_fdsets( "Thread1 result: ", 8, &rd_res, &wr_res, NULL );
pselect_wakeups++;
}
 
pthread_sigmask( SIG_SETMASK, &oldmask, NULL );
 
pthread_exit(arg);
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry2( void *arg)
{
struct timespec zzz;
int err;
zzz.tv_sec = 0;
zzz.tv_nsec = 10*1000000;
CYG_TEST_INFO( "Thread 2: running" );
 
CYG_TEST_INFO( "Thread 2: sleeping" );
nanosleep( &zzz, NULL );
nanosleep( &zzz, NULL );
nanosleep( &zzz, NULL );
while( sigusr1_sent < 20000 )
{
nanosleep( &zzz, NULL );
 
err = pthread_kill( thread1, SIGUSR1 );
if( err < 0 ) SHOW_RESULT( pthread_kill, err );
 
sigusr1_sent++;
 
if( (sigusr1_sent % 500) == 0 )
diag_printf("INFO: <Thread 2: %d signals sent>\n",sigusr1_sent);
}
 
running = false;
CYG_TEST_INFO( "Thread 2: exit" );
pthread_exit( arg );
}
 
//==========================================================================
// main
 
int main( int argc, char **argv )
{
void *retval;
pthread_attr_t attr;
struct sched_param schedparam;
 
CYG_TEST_INIT();
 
sa.sin_family = AF_INET;
sa.sin_len = sizeof(sa);
inet_aton("127.0.0.1", &sa.sin_addr);
sa.sin_port = htons(1234);
init_all_network_interfaces();
// Create test threads
 
{
pthread_attr_init( &attr );
 
schedparam.sched_priority = 5;
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
pthread_attr_setschedparam( &attr, &schedparam );
pthread_attr_setstackaddr( &attr, (void *)&thread1_stack[sizeof(thread1_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread1_stack) );
 
pthread_create( &thread1,
&attr,
pthread_entry1,
(void *)0x12345671);
}
 
{
pthread_attr_init( &attr );
 
schedparam.sched_priority = 10;
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
pthread_attr_setschedparam( &attr, &schedparam );
pthread_attr_setstackaddr( &attr, (void *)&thread2_stack[sizeof(thread2_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread2_stack) );
 
pthread_create( &thread2,
&attr,
pthread_entry2,
(void *)0x12345672);
}
// Now join with thread1
CYG_TEST_INFO( "Main: calling pthread_join(thread1)");
pthread_join( thread1, &retval );
 
// And thread 2
CYG_TEST_INFO( "Main: calling pthread_join(thread2)");
pthread_join( thread2, &retval );
 
diag_printf("INFO: pselect returns: %d\n", pselect_wakeups );
diag_printf("INFO: pselect EINTR returns: %d\n", pselect_eintr );
diag_printf("INFO: SIGUSR1 sent: %d\n", sigusr1_sent );
diag_printf("INFO: SIGUSR1 delivered: %d\n", sigusr1_calls );
CYG_TEST_CHECK( sigusr1_sent == sigusr1_calls, "SIGUSR1 calls != delivered");
CYG_TEST_CHECK( sigusr1_sent == pselect_eintr, "SIGUSR1 calls != pselect EINTR wakeups");
CYG_TEST_PASS_FINISH("pselect");
}
 
#else
 
//==========================================================================
// main
 
void cyg_start(void)
{
CYG_TEST_INIT();
 
CYG_TEST_NA(NA_MSG);
}
 
#endif
 
/v2_0/tests/stdio.c
0,0 → 1,179
//==========================================================================
//
// stdio.c
//
// Test stdio integration of fileio system
//
//==========================================================================
//####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: Test stdio integration of fileio system
// Description: This test uses the testfs to check that the options
// in the STDIO package that enable use of the fileio
// API work correctly.
//
//
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <stdio.h>
#include <string.h>
 
#include <cyg/infra/testcase.h>
#include <cyg/infra/diag.h> // HAL polled output
 
//==========================================================================
// Include the test filesystem.
// If we could make tests out of multiple files, then we could just link
// against the object file for this rather than including it.
 
#include "testfs.c"
 
//==========================================================================
 
#define SHOW_RESULT( _fn, _res ) \
diag_printf("<INFO>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
 
 
#ifdef CYGPKG_LIBC_STDIO
 
//==========================================================================
// main
 
int main( int argc, char **argv )
{
int err;
FILE *f;
fpos_t fpos;
int flibble = 4567;
char *wibble = "abcdefghijk";
 
int flibble1;
char wibble1[20];
CYG_TEST_INIT();
 
f = fopen("/foo", "w" );
if( f == NULL ) SHOW_RESULT( fopen, -1 );
 
err = fprintf(f, "flibble %d wibble %s\n", flibble, wibble );
if( err < 0 ) SHOW_RESULT( fprintf, err );
err = fprintf(f, "another flibble %d another wibble %s\n", flibble, wibble );
if( err < 0 ) SHOW_RESULT( fprintf, err );
err = fclose( f );
if( err == EOF ) SHOW_RESULT( fclose, -1 );
 
 
f = fopen("/foo", "r" );
if( f == NULL ) SHOW_RESULT( fopen, -1 );
 
err = fscanf(f, "flibble %d wibble %s\n", &flibble1, wibble1 );
if( err < 0 ) SHOW_RESULT( fscanf, err );
 
diag_printf("<INFO>: flibble1 %d wibble1 %s\n",flibble1,wibble1);
CYG_TEST_CHECK( flibble1 == flibble , "Bad flibble result from fscanf");
CYG_TEST_CHECK( strcmp(wibble,wibble1) == 0, "Bad wibble result from fscanf");
 
 
err = fgetpos( f, &fpos );
if( err < 0 ) SHOW_RESULT( fgetpos, err );
err = fseek( f, 0, SEEK_SET );
if( err < 0 ) SHOW_RESULT( fseek, err );
 
err = fscanf(f, "flibble %d wibble %s\n", &flibble1, wibble1 );
if( err < 0 ) SHOW_RESULT( fscanf, err );
 
diag_printf("<INFO>: flibble1 %d wibble1 %s\n",flibble1,wibble1);
CYG_TEST_CHECK( flibble1 == flibble , "Bad flibble result from fscanf");
CYG_TEST_CHECK( strcmp(wibble,wibble1) == 0, "Bad wibble result from fscanf");
 
 
err = fseek( f, 0, SEEK_END );
if( err < 0 ) SHOW_RESULT( fseek, err );
 
err = fsetpos( f, &fpos );
if( err < 0 ) SHOW_RESULT( fsetpos, err );
err = fscanf(f, "another flibble %d another wibble %s\n", &flibble1, wibble1 );
if( err < 0 ) SHOW_RESULT( fscanf, err );
 
diag_printf("<INFO>: flibble1 %d wibble1 %s\n",flibble1,wibble1);
CYG_TEST_CHECK( flibble1 == flibble , "Bad flibble result from fscanf");
CYG_TEST_CHECK( strcmp(wibble,wibble1) == 0, "Bad wibble result from fscanf");
 
 
err = fclose( f );
 
 
CYG_TEST_PASS_FINISH("stdio");
return 0;
}
 
#else
 
// -------------------------------------------------------------------------
 
int main( int argc, char **argv )
{
 
CYG_TEST_INIT();
 
CYG_TEST_NA("stdio");
}
 
#endif
 
// -------------------------------------------------------------------------
// EOF stdio.c
/v2_0/tests/socket.c
0,0 → 1,352
//==========================================================================
//
// socket.c
//
// Test socket API
//
//==========================================================================
//####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: Test socket API
// Description: This program tests the socket API. Note that it is only
// intended to test the API and not the functionality of
// the underlying network stack. That is assumed to have
// been established by other tests elsewhere.
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
 
#define __ECOS 1
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <cyg/infra/testcase.h>
 
#if defined(CYGPKG_NET) && defined(CYGPKG_POSIX)
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
 
#include <network.h>
#include <arpa/inet.h>
 
#include <pthread.h>
#include <signal.h>
 
 
#include <cyg/infra/diag.h> // HAL polled output
 
//--------------------------------------------------------------------------
 
#define SHOW_RESULT( _fn, _res ) \
diag_printf(#_fn " returned %d %s\n", _res, _res<0?strerror(errno):"");
 
//--------------------------------------------------------------------------
// Thread stack.
 
char thread1_stack[PTHREAD_STACK_MIN*2];
char thread2_stack[PTHREAD_STACK_MIN*2];
 
//--------------------------------------------------------------------------
// Local variables
 
// Thread IDs
pthread_t thread1;
pthread_t thread2;
 
struct sockaddr_in sa;
 
//--------------------------------------------------------------------------
// test buffers
 
#define TEST_BUFSIZE 512
 
static char buf1[TEST_BUFSIZE];
static char buf2[TEST_BUFSIZE];
static char buf3[TEST_BUFSIZE];
 
//--------------------------------------------------------------------------
 
void *pthread_entry1( void *arg)
{
int fd, fd2;
struct sockaddr_in accsa;
socklen_t accsa_len = sizeof(accsa);
int err;
// int one = 1;
// int so1 = sizeof(one);
fd_set rd;
int i;
ssize_t done;
CYG_TEST_INFO( "Thread 1 running" );
 
CYG_TEST_INFO( "Thread1: calling socket()");
fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( fd < 0 ) SHOW_RESULT( socket, fd );
CYG_TEST_CHECK( fd >= 0, "socket() returned error");
 
// err = setsockopt( fd, SOL_SOCKET, SO_DONTROUTE, (void *)&one, so1);
// if( err < 0 ) SHOW_RESULT( setsockopt, err );
// CYG_TEST_CHECK( err == 0, "setsockopt() returned error");
 
CYG_TEST_INFO( "Thread1: calling bind()");
err = bind( fd, (struct sockaddr *)&sa, sizeof(sa));
if( err < 0 ) SHOW_RESULT( bind, err );
CYG_TEST_CHECK( err == 0, "bind() returned error");
 
CYG_TEST_INFO( "Thread1: calling listen()");
err = listen( fd, 1);
if( err < 0 ) SHOW_RESULT( listen, err );
CYG_TEST_CHECK( err == 0, "listen() returned error");
 
FD_ZERO( &rd );
FD_SET( fd, &rd );
 
CYG_TEST_INFO( "Thread1: calling select()");
err = select( fd+1, &rd, NULL, NULL, NULL );
if( err < 0 ) SHOW_RESULT( select, err );
CYG_TEST_CHECK( err >= 0, "select() returned error");
CYG_TEST_CHECK( FD_ISSET( fd, &rd ), "Fd not set in select() result");
 
CYG_TEST_INFO( "Thread1: calling accept()");
fd2 = accept( fd, (struct sockaddr *)&accsa, &accsa_len );
if( fd2 < 0 ) SHOW_RESULT( accept, fd2 );
CYG_TEST_CHECK( fd2 >= 0, "accept() returned error");
 
 
for( i = 0; i < TEST_BUFSIZE; i++ ) buf1[i] = i;
 
CYG_TEST_INFO( "Thread1: calling write()");
done = write( fd2, buf1, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( write, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "write() returned bad size");
 
FD_ZERO( &rd );
FD_SET( fd2, &rd );
 
CYG_TEST_INFO( "Thread1: calling select()");
err = select( fd2+1, &rd, NULL, NULL, NULL );
if( err < 0 ) SHOW_RESULT( select, err );
CYG_TEST_CHECK( err >= 0, "select() returned error");
CYG_TEST_CHECK( FD_ISSET( fd2, &rd ), "Fd2 not set in select() result");
CYG_TEST_INFO( "Thread1: calling read()");
done = read( fd2, buf3, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( read, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "read() returned bad size");
 
for( i = 0; i < TEST_BUFSIZE; i++ )
if( buf1[i] != buf3[i] )
diag_printf("buf1[%d](%02x) != buf3[%d](%02x)\n",i,buf1[i],i,buf3[i]);
 
CYG_TEST_INFO( "Thread1: calling close(fd)");
err = close(fd);
if( err < 0 ) SHOW_RESULT( close, err );
CYG_TEST_CHECK( err == 0, "close() returned error");
 
CYG_TEST_INFO( "Thread1: calling close(fd2)");
err = close(fd2);
if( err < 0 ) SHOW_RESULT( close, err );
CYG_TEST_CHECK( err == 0, "close() returned error");
CYG_TEST_INFO( "Thread1: calling pthread_exit()");
pthread_exit( arg );
}
 
//--------------------------------------------------------------------------
 
void *pthread_entry2( void *arg)
{
int fd;
int err;
// int one = 1;
// int so1 = sizeof(one);
int i;
ssize_t done;
fd_set rd;
CYG_TEST_INFO( "Thread 2 running" );
 
CYG_TEST_INFO( "Thread2: calling socket()");
fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if( fd < 0 ) SHOW_RESULT( socket, fd );
CYG_TEST_CHECK( fd >= 0, "socket() returned error");
 
// err = setsockopt( fd, SOL_SOCKET, SO_DONTROUTE, (void *)&one, so1);
// if( err < 0 ) SHOW_RESULT( setsockopt, err );
// CYG_TEST_CHECK( err == 0, "setsockopt() returned error");
 
CYG_TEST_INFO( "Thread2: calling connect()");
err = connect( fd, (struct sockaddr *)&sa, sizeof(sa));
if( err < 0 ) SHOW_RESULT( connect, err );
CYG_TEST_CHECK( err == 0, "connect() returned error");
 
FD_ZERO( &rd );
FD_SET( fd, &rd );
 
CYG_TEST_INFO( "Thread2: calling select()");
err = select( fd+1, &rd, NULL, NULL, NULL );
if( err < 0 ) SHOW_RESULT( select, err );
CYG_TEST_CHECK( err >= 0, "select() returned error");
CYG_TEST_CHECK( FD_ISSET( fd, &rd ), "Fd not set in select() result");
 
CYG_TEST_INFO( "Thread2: calling read()");
done = read( fd, buf2, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( read, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "read() returned bad size");
 
for( i = 0; i < TEST_BUFSIZE; i++ )
if( buf1[i] != buf2[i] )
diag_printf("buf1[%d](%02x) != buf2[%d](%02x)\n",i,buf1[i],i,buf2[i]);
 
CYG_TEST_INFO( "Thread2: calling write()");
done = write( fd, buf2, TEST_BUFSIZE);
if( done != TEST_BUFSIZE ) SHOW_RESULT( write, done );
CYG_TEST_CHECK( done == TEST_BUFSIZE, "write() returned bad size");
 
CYG_TEST_INFO( "Thread2: calling close(fd)");
err = close(fd);
if( err < 0 ) SHOW_RESULT( close, err );
CYG_TEST_CHECK( err == 0, "close() returned error");
CYG_TEST_INFO( "Thread2: calling pthread_exit()");
pthread_exit( arg );
}
 
//==========================================================================
// main
 
int main( int argc, char **argv )
{
struct in_addr ina;
char *addr1 = "127.0.255.106";
char *addr2;
void *retval;
pthread_attr_t attr;
struct sched_param schedparam;
sa.sin_family = AF_INET;
sa.sin_len = sizeof(sa);
inet_aton("127.0.0.1", &sa.sin_addr);
sa.sin_port = htons(1234);
CYG_TEST_INIT();
 
init_all_network_interfaces();
// Test inet_ntoa() and inet_aton()
 
inet_aton(addr1, &ina);
addr2 = inet_ntoa(ina);
CYG_TEST_CHECK( strcmp(addr1, addr2) == 0, "Bad inet adderess conversion");
 
 
// Create test threads
 
{
pthread_attr_init( &attr );
 
schedparam.sched_priority = 10;
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
pthread_attr_setschedparam( &attr, &schedparam );
pthread_attr_setstackaddr( &attr, (void *)&thread1_stack[sizeof(thread1_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread1_stack) );
 
pthread_create( &thread1,
&attr,
pthread_entry1,
(void *)0x12345671);
}
 
{
pthread_attr_init( &attr );
 
schedparam.sched_priority = 5;
pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
pthread_attr_setschedpolicy( &attr, SCHED_RR );
pthread_attr_setschedparam( &attr, &schedparam );
pthread_attr_setstackaddr( &attr, (void *)&thread2_stack[sizeof(thread2_stack)] );
pthread_attr_setstacksize( &attr, sizeof(thread2_stack) );
 
pthread_create( &thread2,
&attr,
pthread_entry2,
(void *)0x12345672);
}
// Now join with thread1
CYG_TEST_INFO( "Main: calling pthread_join(thread1)");
pthread_join( thread1, &retval );
 
// And thread 2
CYG_TEST_INFO( "Main: calling pthread_join(thread2)");
pthread_join( thread2, &retval );
 
CYG_TEST_PASS_FINISH("socket");
}
 
#else
 
//==========================================================================
// main
 
int main( int argc, char **argv )
{
CYG_TEST_INIT();
 
CYG_TEST_NA("socket");
}
 
#endif
 
 
// -------------------------------------------------------------------------
// EOF socket.c
/v2_0/tests/testfs.c
0,0 → 1,1249
//==========================================================================
//
// testfs.c
//
// Test file system
//
//==========================================================================
//####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: Test file system
// Description: This is a very simple implementation of a RAM file system.
// This implementation is not "industrial strength" or suitable
// for production use, it is too wasteful of both memory and time.
// Its primary purpose is to support testing of the fileio
// infrastructure and API. It can, however, serve as a model
// and source of code fragments for the implementation
// of further filesystems.
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
 
#include <cyg/fileio/fileio.h>
 
#include <cyg/kernel/kapi.h>
#include <cyg/infra/diag.h>
 
//==========================================================================
// Configuration parameters
 
#define TESTFS_NFILE 10 // Max number of files/directories
#define TESTFS_NBLOCK 20 // Number of data blocks available
#define TESTFS_BLOCKSIZE 128 // Bytes stored per block
#define TESTFS_FILEBLOCKS 8 // Max blocks per file
#define TESTFS_NAMESIZE 32 // Length of file names in bytes
 
 
// Maximum file size is blocksize*blocks
#define TESTFS_FILESIZE_MAX (TESTFS_BLOCKSIZE*TESTFS_FILEBLOCKS)
 
//==========================================================================
// Data structures
 
struct testfs_node;
typedef struct testfs_node testfs_node;
 
struct testfs_block;
typedef struct testfs_block testfs_block;
 
 
struct testfs_node
{
testfs_node *next; // next node in list
testfs_node *parent; // Back pointer to parent
int refcnt; // reference count
char name[TESTFS_NAMESIZE]; // file name
struct stat status; // status data
union
{
struct
{
testfs_block *data[TESTFS_FILEBLOCKS]; // array of blocks
} file;
 
struct
{
testfs_node *nodes[TESTFS_FILEBLOCKS]; // array of nodes
} dir;
} u;
};
 
struct testfs_block
{
union
{
testfs_block *next; // next block in free list
testfs_node *file; // back pointer to file
} u;
off_t pos; // position in file of first byte
size_t size; // number of bytes in buffer
char data[TESTFS_BLOCKSIZE]; // the data
};
 
//==========================================================================
// Local data
 
// Array of nodes
static testfs_node node[TESTFS_NFILE];
 
// node free list.
static testfs_node *free_node = NULL;
 
// Array of data blocks
static testfs_block block[TESTFS_NBLOCK];
 
// block free list.
static testfs_block *free_block = NULL;
 
// Init flag
cyg_bool testfs_initialized = false;
 
//==========================================================================
// Forward definitions
 
// Filesystem operations
static int testfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
static int testfs_umount ( cyg_mtab_entry *mte );
static int testfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *fte );
static int testfs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int testfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int testfs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int testfs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 );
static int testfs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type );
static int testfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *fte );
static int testfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out );
static int testfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf);
static int testfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
static int testfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
 
// File operations
static int testfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int testfs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int testfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
static int testfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
//static int testfs_fo_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
static int testfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode );
static int testfs_fo_close (struct CYG_FILE_TAG *fp);
static int testfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf );
static int testfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
static int testfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
 
// Directory operations
static int testfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int testfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
 
//==========================================================================
// Filesystem table entries
 
FSTAB_ENTRY( testfs_fste, "testfs", 0,
CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
testfs_mount,
testfs_umount,
testfs_open,
testfs_unlink,
testfs_mkdir,
testfs_rmdir,
testfs_rename,
testfs_link,
testfs_opendir,
testfs_chdir,
testfs_stat,
testfs_getinfo,
testfs_setinfo);
 
MTAB_ENTRY( testfs_mte1,
"/",
"testfs",
"",
0);
 
#if 0
MTAB_ENTRY( testfs_mte2,
"/ram",
"testfs",
"",
0);
#endif
 
static cyg_fileops testfs_fileops =
{
testfs_fo_read,
testfs_fo_write,
testfs_fo_lseek,
testfs_fo_ioctl,
cyg_fileio_seltrue,
testfs_fo_fsync,
testfs_fo_close,
testfs_fo_fstat,
testfs_fo_getinfo,
testfs_fo_setinfo
};
 
static cyg_fileops testfs_dirops =
{
testfs_fo_dirread,
(cyg_fileop_write *)cyg_fileio_enosys,
testfs_fo_dirlseek,
(cyg_fileop_ioctl *)cyg_fileio_enosys,
cyg_fileio_seltrue,
(cyg_fileop_fsync *)cyg_fileio_enosys,
testfs_fo_close,
(cyg_fileop_fstat *)cyg_fileio_enosys,
(cyg_fileop_getinfo *)cyg_fileio_enosys,
(cyg_fileop_setinfo *)cyg_fileio_enosys
};
 
//==========================================================================
// Support routines
 
// -------------------------------------------------------------------------
// Local strcmp() and strcpy()
 
static int strcmp( const char *s1, const char *s2 )
{
while( *s1 == *s2 && *s1 != '\0' && *s2 != '\0' )
s1++, s2++;
 
return (*s2)-(*s1);
}
 
static char *strcpy( char *s1, const char *s2 )
{
char *s = s1;
while( (*s1++ = *s2++) != 0);
return s;
}
 
// -------------------------------------------------------------------------
// Follow a path through the directory structure
 
static int testfs_find( testfs_node *dir, // dir to start search in
const char *path, // path to follow
testfs_node **found, // return node found
testfs_node **parent, // return last dir searched
char *name, // name fragment buffer
cyg_bool *lastp) // last name in path ?
{
testfs_node *nd = dir;
 
*lastp = false;
*found = NULL;
while( *path != '\0' )
{
const char *p = path;
char *n = name;
testfs_node *nd1;
int i;
 
// check nd is a directory
if( !S_ISDIR(nd->status.st_mode) ) return ENOTDIR;
 
// Isolate the next element of the path name.
while( *p != '\0' && *p != '/' && (n-&name[0]) < TESTFS_NAMESIZE)
*n++ = *p++;
 
if( (n-&name[0]) >= TESTFS_NAMESIZE )
return ENAMETOOLONG;
 
// Step path on past the separator
// If this is the last name element in the path,
// set *lastp to indicate this.
if( *(path=p) == '/' ) path++;
else *lastp = true;
 
// teminate name
*n = '\0';
 
// name now contains the next path element, search the node
// in nd for it.
 
*parent = nd;
nd1 = NULL;
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
{
testfs_node *n = nd->u.dir.nodes[i];
if( n == NULL )
continue;
 
if( strcmp( name, n->name ) == 0 )
{
nd1 = n;
break;
}
}
if( nd1 == NULL ) return ENOENT;
 
nd = nd1;
}
 
// Return what we have found
*found = nd;
return ENOERR;
}
 
// -------------------------------------------------------------------------
// Get current time since epoch
 
static time_t testfs_time(void)
{
// FIXME: !!!!Temporary!!!!
return cyg_current_time();
}
 
// -------------------------------------------------------------------------
 
static int testfs_delnode( testfs_node *nd )
{
 
testfs_node *parent;
int i;
 
// Non-unitary ref count means this node is either open
// or is a dir with entries in it.
if( nd->refcnt > 1 )
return EBUSY;
 
// Remove from parent's node list.
parent = nd->parent;
 
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
if( parent->u.dir.nodes[i] == nd )
{
parent->u.dir.nodes[i] = NULL;
break;
}
 
parent->refcnt--;
 
if( S_ISREG(nd->status.st_mode) )
{
// for a file, return blocks to free list
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
{
testfs_block *b = nd->u.file.data[i];
if( b != NULL )
{
b->u.next = free_block;
b->pos = -1;
free_block = b;
}
}
}
 
// and finally return nd to free node list
 
nd->next = free_node;
nd->refcnt = -1;
free_node = nd;
 
return ENOERR;
}
 
//==========================================================================
// Filesystem operations
 
// -------------------------------------------------------------------------
 
static int testfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
{
testfs_node *root;
int i;
if( !testfs_initialized )
{
int i;
 
for( i = 0; i < TESTFS_NFILE; i++ )
{
node[i].next = free_node;
node[i].refcnt = -1;
free_node = &node[i];
}
 
for( i = 0; i < TESTFS_NBLOCK; i++ )
{
block[i].u.next = free_block;
block[i].pos = -1;
free_block = &block[i];
}
 
testfs_initialized = true;
}
 
// Allocate a node to be the root of this filesystem and
// initialize it.
 
root = free_node;
if( root == NULL ) return ENOSPC;
 
free_node = root->next;
 
root->next = root; // form circular list
root->parent = root; // I'm my own parent!
root->refcnt = 1; // don't want to ever lose root
strcpy( root->name, "root");
root->status.st_mode = __stat_mode_DIR;
root->status.st_ino = root-&node[0];
root->status.st_dev = 0;
root->status.st_nlink = 1;
root->status.st_uid = 0;
root->status.st_gid = 0;
root->status.st_size = 0;
root->status.st_atime = testfs_time();
root->status.st_mtime = testfs_time();
root->status.st_ctime = testfs_time();
 
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
root->u.dir.nodes[i] = NULL;
mte->root = (cyg_dir)root;
return 0;
}
 
// -------------------------------------------------------------------------
 
static int testfs_umount ( cyg_mtab_entry *mte )
{
testfs_node *root = (testfs_node *)mte->root;
 
// Non-empty filesystem, do not unmount
if( root->refcnt != 1 )
return EBUSY;
 
// Otherwise just return it to the free pool
root->next = free_node;
root->refcnt = -1;
free_node = root;
 
// Clear root pointer
mte->root = CYG_DIR_NULL;
// That's all folks.
return ENOERR;
}
// -------------------------------------------------------------------------
 
static int testfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
int mode, cyg_file *file )
{
testfs_node *nd, *parent;
int err;
char name[TESTFS_NAMESIZE];
cyg_bool lastp;
err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
 
if( lastp && err == ENOENT && (mode & O_CREAT) )
{
int i;
// No node there, if the O_CREAT bit is set then we must
// create a new one. The parent and name results will have been filled
// in, so we know where to put it.
 
// first check that there is space for it
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
if( parent->u.dir.nodes[i] == NULL )
break;
 
if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
// Allocate a new node
nd = free_node;
if( nd == NULL ) return ENOSPC;
free_node = nd->next;
 
// Add to directory list
parent->u.dir.nodes[i] = nd;
 
parent->refcnt++;
// Fill in details
nd->parent = parent;
nd->refcnt = 1; // 1 for directory reference
strcpy( nd->name, name);
nd->status.st_mode = __stat_mode_REG;
nd->status.st_ino = nd-&node[0];
nd->status.st_dev = 0;
nd->status.st_nlink = 1;
nd->status.st_uid = 0;
nd->status.st_gid = 0;
nd->status.st_size = 0;
nd->status.st_atime = testfs_time();
nd->status.st_mtime = testfs_time();
nd->status.st_ctime = testfs_time();
 
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
nd->u.file.data[i] = NULL;
 
err = ENOERR;
}
 
if( err == ENOERR && (mode & O_TRUNC ) )
{
// Clean out any blocks in the file...
 
int i;
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
{
testfs_block *b = nd->u.file.data[i];
if( b != NULL )
{
b->u.next = free_block;
b->pos = -1;
free_block = b;
nd->u.file.data[i] = NULL;
}
}
 
nd->status.st_size = 0;
}
if( err != ENOERR ) return err;
 
if( S_ISDIR(nd->status.st_mode) ) return EISDIR;
 
nd->refcnt++; // Count successful open as a ref
// Initialize the file object
file->f_flag |= mode & CYG_FILE_MODE_MASK;
file->f_type = CYG_FILE_TYPE_FILE;
file->f_ops = &testfs_fileops;
file->f_offset = 0;
file->f_data = (CYG_ADDRWORD)nd;
file->f_xops = 0;
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
{
testfs_node *nd, *parent;
int err;
char name[TESTFS_NAMESIZE];
cyg_bool lastp;
err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
 
if( err != ENOERR ) return err;
 
// Cannot unlink directories, use rmdir() instead
if( S_ISDIR(nd->status.st_mode) )
return EPERM;
 
err = testfs_delnode( nd );
return err;
}
 
// -------------------------------------------------------------------------
 
static int testfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
{
testfs_node *nd, *parent;
int err;
char name[TESTFS_NAMESIZE];
cyg_bool lastp;
err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
 
if( lastp && err == ENOENT )
{
int i;
// No node there, create a new one. The parent and name
// results will have been filled in, so we know where to put
// it.
 
// first check that there is space for it
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
if( parent->u.dir.nodes[i] == NULL )
break;
 
if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
// Allocate a new node
nd = free_node;
if( nd == NULL ) return ENOSPC;
free_node = nd->next;
 
// Add to directory list
parent->u.dir.nodes[i] = nd;
 
parent->refcnt++;
// Fill in details
nd->parent = parent;
nd->refcnt = 1; // 1 for directory reference
strcpy( nd->name, name);
nd->status.st_mode = __stat_mode_DIR;
nd->status.st_ino = nd-&node[0];
nd->status.st_dev = 0;
nd->status.st_nlink = 1;
nd->status.st_uid = 0;
nd->status.st_gid = 0;
nd->status.st_size = 0;
nd->status.st_atime = testfs_time();
nd->status.st_mtime = testfs_time();
nd->status.st_ctime = testfs_time();
 
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
nd->u.dir.nodes[i] = NULL;
err = ENOERR;
}
 
return err;
}
 
// -------------------------------------------------------------------------
 
static int testfs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
{
testfs_node *nd, *parent;
int err;
char name[TESTFS_NAMESIZE];
cyg_bool lastp;
err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
 
if( err != ENOERR ) return err;
 
// Check that it is a directory
if( !S_ISDIR(nd->status.st_mode) )
return EPERM;
 
err = testfs_delnode( nd );
 
return err;
}
 
// -------------------------------------------------------------------------
 
static int testfs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *path1,
cyg_dir dir2, const char *path2 )
{
testfs_node *nd1, *parent1;
testfs_node *nd2, *parent2;
int err;
char name1[TESTFS_NAMESIZE];
char name2[TESTFS_NAMESIZE];
cyg_bool lastp;
int i,j;
err = testfs_find( (testfs_node *)dir1, path1, &nd1, &parent1, name1, &lastp );
 
if( err != ENOERR ) return err;
 
err = testfs_find( (testfs_node *)dir2, path2, &nd2, &parent2, name2, &lastp );
 
// Allow through renames to non-existent objects.
if( lastp && err == ENOENT )
err = ENOERR;
if( err != ENOERR ) return err;
 
// Null rename, just return
if( nd1 == nd2 )
return ENOERR;
 
// First deal with any node that is at the destination
if( nd2 )
{
// Check that we are renaming like-for-like
 
if( !S_ISDIR(nd1->status.st_mode) && S_ISDIR(nd2->status.st_mode) )
return EISDIR;
 
if( S_ISDIR(nd1->status.st_mode) && !S_ISDIR(nd2->status.st_mode) )
return ENOTDIR;
 
// Now delete the destination node.
err = testfs_delnode( nd2 );
if( err != ENOERR ) return err;
}
 
// Now we know that there is no clashing node at the destination.
// Move the node over and change its name.
 
// first check that there is space for it
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
if( parent2->u.dir.nodes[i] == NULL )
break;
 
if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
 
// Now remove node from old parent.
for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
if( parent1->u.dir.nodes[j] == nd1 )
{
parent1->u.dir.nodes[j] = NULL;
break;
}
 
parent1->refcnt--;
 
// Add to directory list
parent2->u.dir.nodes[i] = nd1;
parent2->refcnt++;
nd1->parent = parent2;
// And give it a new name.
strcpy( nd1->name, name2 );
return err;
}
 
// -------------------------------------------------------------------------
 
static int testfs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *path1,
cyg_dir dir2, const char *path2, int type )
{
// The data structures of this file system do not support the
// creation of links.
return ENOSYS;
}
 
// -------------------------------------------------------------------------
 
static int testfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
cyg_file *file )
{
testfs_node *nd, *parent;
int err;
char name[TESTFS_NAMESIZE];
cyg_bool lastp;
err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
 
if( err != ENOERR ) return err;
 
if( !S_ISDIR(nd->status.st_mode) )
return ENOTDIR;
 
nd->refcnt++; // Count successful open as a ref
// Initialize the file object
file->f_type = CYG_FILE_TYPE_FILE;
file->f_ops = &testfs_dirops;
file->f_offset = 0;
file->f_data = (CYG_ADDRWORD)nd;
file->f_xops = 0;
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
cyg_dir *dir_out )
{
if( dir_out != NULL )
{
// This is a request to get a new directory pointer in
// *dir_out.
 
testfs_node *nd, *parent;
int err;
char name[TESTFS_NAMESIZE];
cyg_bool lastp;
err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
 
if( err != ENOERR ) return err;
 
if( !S_ISDIR(nd->status.st_mode) )
return ENOTDIR;
// Increment ref count to keep this directory in existent
// while it is the current cdir.
nd->refcnt++;
 
// Pass it out
*dir_out = (cyg_dir)nd;
}
else
{
// If no output dir is required, this means that the mte and
// dir arguments are the current cdir setting and we should
// forget this fact.
 
testfs_node *nd = (testfs_node *)dir;
 
// Just decrement reference count.
nd->refcnt--;
}
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
struct stat *buf)
{
testfs_node *nd, *parent;
int err;
char name[TESTFS_NAMESIZE];
cyg_bool lastp;
err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
 
if( err != ENOERR ) return err;
 
*buf = nd->status;
return err;
}
 
// -------------------------------------------------------------------------
 
static int testfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
int key, void *buf, int len )
{
return ENOSYS;
}
 
// -------------------------------------------------------------------------
 
static int testfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
int key, void *buf, int len )
{
return ENOSYS;
}
 
 
//==========================================================================
// File operations
 
 
// -------------------------------------------------------------------------
 
static int testfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
testfs_node *nd = (testfs_node *)fp->f_data;
int i;
off_t pos = fp->f_offset;
 
for( i = 0; i < uio->uio_iovcnt; i++ )
{
cyg_iovec *iov = &uio->uio_iov[i];
char *buf = (char *)iov->iov_base;
off_t len = iov->iov_len;
 
while( len > 0 && pos < nd->status.st_size )
{
testfs_block *b = nd->u.file.data[pos/TESTFS_BLOCKSIZE];
off_t l = len;
off_t bpos = pos%TESTFS_BLOCKSIZE;
// If there is no block in that pos, we have reached
// the end of the file.
if( b == NULL ) return ENOERR;
 
// adjust size to this block
if( l > (b->size-bpos) )
l = (b->size-bpos);
 
// copy data out
memcpy( buf, &b->data[bpos], l );
 
uio->uio_resid -= l;
len -= l;
buf += l;
pos += l;
 
// keep offset up to date incase of errors
fp->f_offset = pos;
}
}
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
testfs_node *nd = (testfs_node *)fp->f_data;
int i;
off_t pos = fp->f_offset;
// Check we are not at end of allowed max file size
if( pos >= TESTFS_FILESIZE_MAX )
return EFBIG;
 
// Check that pos is within current file size, or at the very end.
if( pos < 0 || pos > nd->status.st_size )
return EINVAL;
 
// Now loop over the iovecs until they are all done, or
// we get an error.
for( i = 0; i < uio->uio_iovcnt; i++ )
{
cyg_iovec *iov = &uio->uio_iov[i];
char *buf = (char *)iov->iov_base;
off_t len = iov->iov_len;
 
while( len > 0 )
{
testfs_block *b = nd->u.file.data[pos/TESTFS_BLOCKSIZE];
off_t l = len;
off_t bpos = pos%TESTFS_BLOCKSIZE;
// If there is no block in that pos, allocate one
// and initialize it
if( b == NULL )
{
b = free_block;
if( b == NULL ) return ENOSPC;
free_block = b->u.next;
nd->u.file.data[pos/TESTFS_BLOCKSIZE] = b;
b->u.file = nd;
b->pos = pos;
b->size = 0;
}
 
// adjust size to this block
if( l > (TESTFS_BLOCKSIZE-bpos) )
l = (TESTFS_BLOCKSIZE-bpos);
 
// copy data in
memcpy( &b->data[bpos], buf, l );
 
// adjust buffer info
if( b->size < bpos+l )
b->size = bpos+l;
uio->uio_resid -= l;
len -= l;
buf += l;
pos += l;
 
// keep node size and file offset up to date
//in case of an error.
if( pos > nd->status.st_size )
nd->status.st_size = pos;
fp->f_offset = pos;
 
if( pos >= TESTFS_FILESIZE_MAX )
return EFBIG;
}
}
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
{
testfs_node *nd = (testfs_node *)fp->f_data;
off_t pos = *apos;
 
switch( whence )
{
case SEEK_SET:
// we are already where we want to be.
break;
 
case SEEK_CUR:
pos += fp->f_offset;
break;
 
case SEEK_END:
pos += nd->status.st_size;
break;
 
default:
return EINVAL;
}
// Check that pos is within current file size, or at the very end.
if( pos < 0 || pos > nd->status.st_size )
return EINVAL;
 
// All OK, set fp offset.
*apos = fp->f_offset = pos;
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data)
{
return ENOSYS;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode )
{
// Nothing to do
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_close (struct CYG_FILE_TAG *fp)
{
testfs_node *nd = (testfs_node *)fp->f_data;
 
nd->refcnt--; // remove open count
 
fp->f_data = 0; // clear data pointer
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf )
{
testfs_node *nd = (testfs_node *)fp->f_data;
 
*buf = nd->status;
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
{
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
{
return ENOERR;
}
 
 
//==========================================================================
// Directory operations
 
static int testfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
testfs_node *nd = (testfs_node *)fp->f_data;
off_t pos = fp->f_offset;
cyg_iovec *iov = &uio->uio_iov[0];
char *buf = (char *)iov->iov_base;
off_t len = iov->iov_len;
 
// End of directory
if( pos >= TESTFS_FILEBLOCKS )
return ENOERR;
 
if( len < sizeof(struct dirent) )
return EINVAL;
for( ; pos < TESTFS_FILEBLOCKS; pos++ )
if( nd->u.dir.nodes[pos] != NULL )
{
struct dirent *ent = (struct dirent *)buf;
strcpy( ent->d_name, nd->u.dir.nodes[pos]->name );
uio->uio_resid -= sizeof(struct dirent);
break;
}
 
fp->f_offset = pos+1;
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int testfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
{
if( whence != SEEK_SET || *pos != 0)
return EINVAL;
 
*pos = fp->f_offset = 0;
return ENOERR;
}
 
//==========================================================================
// Filesystem dump
// Dumps out the node and block arrays in a readable format, and does
// a little consistency checking as it goes.
 
void testfs_dump(void)
{
int errors = 0;
int i;
char *indent = "\n |";
 
diag_printf("Nodes:\n");
for( i = 0; i < TESTFS_NFILE; i++ )
{
testfs_node *nd = &node[i];
 
diag_printf("%3d : ",i);
if( nd->refcnt < 0 )
diag_printf("<free>");
else if( !S_ISDIR(nd->status.st_mode) )
{
// Regular file
int j;
diag_printf("f %8s %4d |",nd->name,nd->status.st_size);
for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
{
testfs_block *b = nd->u.file.data[j];
if( b != NULL )
{
if( j > 0 && (j%4) == 0 )
diag_printf(indent);
diag_printf(" %3d[%3d,%3d]",b-block,b->pos,b->size);
if( b->u.file != nd )
{
errors++;
diag_printf("!");
}
}
}
}
else
{
// Directory
int j;
int rc = 1;
diag_printf("d %8s |",nd->name);
 
for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
{
testfs_node *n = nd->u.dir.nodes[j];
if( n != NULL )
{
if( j > 0 && (j%4) == 0 )
diag_printf(indent);
diag_printf(" %3d[%7s]",n-node,n->name);
rc++;
}
}
 
if( nd->refcnt != rc )
{
diag_printf("%s refcount is %d should be %d",indent,nd->refcnt,rc);
if( nd->refcnt == rc+1 )
diag_printf(" (but may be current dir)");
}
}
 
diag_printf("\n");
}
 
diag_printf("Blocks:\n");
 
for( i = 0; i < TESTFS_NBLOCK; i++ )
{
testfs_block *b = &block[i];
 
diag_printf("%3d :",i);
if( b->pos == -1 )
diag_printf(" <free>");
else
{
int j;
testfs_node *nd = b->u.file;
diag_printf(" %3d %3d %d[%7s]",b->pos,b->size,nd-node,nd->name);
for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
{
if( nd->u.file.data[j] == b )
break;
}
if( j == TESTFS_FILEBLOCKS )
{
errors++;
diag_printf(" block not in file!");
}
}
diag_printf("\n");
}
 
if( errors != 0 )
diag_printf("%d errors detected\n",errors);
}
 
// -------------------------------------------------------------------------
// EOF testfs.c
/v2_0/tests/fileio1.c
0,0 → 1,465
//==========================================================================
//
// fileio1.c
//
// Test fileio system
//
//==========================================================================
//####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: Test fileio system
// Description: This test uses the testfs to check out the initialization
// and basic operation of the fileio system
//
//
//
//
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
 
#include <cyg/infra/testcase.h>
#include <cyg/infra/diag.h> // HAL polled output
 
//==========================================================================
// Include the test filesystem.
// If we could make tests out of multiple files, then we could just link
// against the object file for this rather than including it.
 
#include "testfs.c"
 
//==========================================================================
 
#define SHOW_RESULT( _fn, _res ) \
diag_printf("<INFO>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
 
//==========================================================================
 
#define IOSIZE 100
 
//==========================================================================
 
static void listdir( char *name, int statp )
{
int err;
DIR *dirp;
diag_printf("<INFO>: reading directory %s\n",name);
dirp = opendir( name );
if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
 
for(;;)
{
struct dirent *entry = readdir( dirp );
if( entry == NULL )
break;
 
diag_printf("<INFO>: entry %14s",entry->d_name);
if( statp )
{
char fullname[PATH_MAX];
struct stat sbuf;
 
if( name[0] )
{
strcpy(fullname, name );
if( !(name[0] == '/' && name[1] == 0 ) )
strcat(fullname, "/" );
}
else fullname[0] = 0;
strcat(fullname, entry->d_name );
err = stat( fullname, &sbuf );
if( err < 0 )
{
if( errno == ENOSYS )
diag_printf(" <no status available>");
else SHOW_RESULT( stat, err );
}
else
{
diag_printf(" [mode %08x nlink %d size %d]",
sbuf.st_mode,sbuf.st_nlink,sbuf.st_size);
}
}
 
diag_printf("\n");
}
 
err = closedir( dirp );
if( err < 0 ) SHOW_RESULT( stat, err );
}
 
//==========================================================================
 
static void createfile( char *name, size_t size )
{
char buf[IOSIZE];
int fd;
ssize_t wrote;
int i;
int err;
 
diag_printf("<INFO>: create file %s size %d\n",name,size);
 
err = access( name, F_OK );
if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
fd = open( name, O_WRONLY|O_CREAT );
if( fd < 0 ) SHOW_RESULT( open, fd );
 
while( size > 0 )
{
ssize_t len = size;
if ( len > IOSIZE ) len = IOSIZE;
wrote = write( fd, buf, len );
if( wrote != len ) SHOW_RESULT( write, wrote );
 
size -= wrote;
}
 
err = close( fd );
if( err < 0 ) SHOW_RESULT( close, err );
}
 
//==========================================================================
 
static void maxfile( char *name )
{
char buf[IOSIZE];
int fd;
ssize_t wrote;
int i;
int err;
size_t size = 0;
diag_printf("<INFO>: create maximal file %s\n",name);
 
err = access( name, F_OK );
if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
fd = open( name, O_WRONLY|O_CREAT );
if( fd < 0 ) SHOW_RESULT( open, fd );
 
do
{
wrote = write( fd, buf, IOSIZE );
if( wrote < 0 ) SHOW_RESULT( write, wrote );
 
size += wrote;
} while( wrote == IOSIZE );
 
diag_printf("<INFO>: file size == %d\n",size);
 
err = close( fd );
if( err < 0 ) SHOW_RESULT( close, err );
}
 
//==========================================================================
 
static void checkfile( char *name )
{
char buf[IOSIZE];
int fd;
ssize_t done;
int i;
int err;
 
diag_printf("<INFO>: check file %s\n",name);
err = access( name, F_OK );
if( err != 0 ) SHOW_RESULT( access, err );
 
fd = open( name, O_RDONLY );
if( fd < 0 ) SHOW_RESULT( open, fd );
 
for(;;)
{
done = read( fd, buf, IOSIZE );
if( done < 0 ) SHOW_RESULT( read, done );
 
if( done == 0 ) break;
 
for( i = 0; i < done; i++ )
if( buf[i] != i%256 )
{
diag_printf("buf[%d](%02x) != %02x\n",i,buf[i],i%256);
CYG_TEST_FAIL("Data read not equal to data written\n");
}
}
 
err = close( fd );
if( err < 0 ) SHOW_RESULT( close, err );
}
 
//==========================================================================
 
static void copyfile( char *name2, char *name1 )
{
 
int err;
char buf[IOSIZE];
int fd1, fd2;
ssize_t done, wrote;
 
diag_printf("<INFO>: copy file %s -> %s\n",name2,name1);
 
err = access( name1, F_OK );
if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
 
err = access( name2, F_OK );
if( err != 0 ) SHOW_RESULT( access, err );
fd1 = open( name1, O_WRONLY|O_CREAT );
if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
 
fd2 = open( name2, O_RDONLY );
if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
for(;;)
{
done = read( fd2, buf, IOSIZE );
if( done < 0 ) SHOW_RESULT( read, done );
 
if( done == 0 ) break;
 
wrote = write( fd1, buf, done );
if( wrote != done ) SHOW_RESULT( write, wrote );
 
if( wrote != done ) break;
}
 
err = close( fd1 );
if( err < 0 ) SHOW_RESULT( close, err );
 
err = close( fd2 );
if( err < 0 ) SHOW_RESULT( close, err );
}
 
//==========================================================================
 
static void comparefiles( char *name2, char *name1 )
{
int err;
char buf1[IOSIZE];
char buf2[IOSIZE];
int fd1, fd2;
ssize_t done1, done2;
int i;
 
diag_printf("<INFO>: compare files %s == %s\n",name2,name1);
 
err = access( name1, F_OK );
if( err != 0 ) SHOW_RESULT( access, err );
 
err = access( name1, F_OK );
if( err != 0 ) SHOW_RESULT( access, err );
fd1 = open( name1, O_RDONLY );
if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
 
fd2 = open( name2, O_RDONLY );
if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
for(;;)
{
done1 = read( fd1, buf1, IOSIZE );
if( done1 < 0 ) SHOW_RESULT( read, done1 );
 
done2 = read( fd2, buf2, IOSIZE );
if( done2 < 0 ) SHOW_RESULT( read, done2 );
 
if( done1 != done2 )
diag_printf("Files different sizes\n");
if( done1 == 0 ) break;
 
for( i = 0; i < done1; i++ )
if( buf1[i] != buf2[i] )
{
diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
CYG_TEST_FAIL("Data in files not equal\n");
}
}
 
err = close( fd1 );
if( err < 0 ) SHOW_RESULT( close, err );
 
err = close( fd2 );
if( err < 0 ) SHOW_RESULT( close, err );
}
 
//==========================================================================
// main
 
int main( int argc, char **argv )
{
int err;
 
CYG_TEST_INIT();
 
// --------------------------------------------------------------
 
createfile( "/foo", 202 );
checkfile( "foo" );
copyfile( "foo", "fee");
checkfile( "fee" );
comparefiles( "foo", "/fee" );
err = mkdir( "/bar", 0 );
if( err < 0 ) SHOW_RESULT( mkdir, err );
 
listdir( "/" , false);
 
copyfile( "fee", "/bar/fum" );
checkfile( "bar/fum" );
comparefiles( "/fee", "bar/fum" );
 
err = chdir( "bar" );
if( err < 0 ) SHOW_RESULT( chdir, err );
err = rename( "/foo", "bundy" );
if( err < 0 ) SHOW_RESULT( rename, err );
 
listdir( "/", true );
listdir( "" , true );
 
checkfile( "/bar/bundy" );
comparefiles("/fee", "bundy" );
 
testfs_dump();
// --------------------------------------------------------------
err = unlink( "/fee" );
if( err < 0 ) SHOW_RESULT( unlink, err );
 
err = unlink( "fum" );
if( err < 0 ) SHOW_RESULT( unlink, err );
 
err = unlink( "/bar/bundy" );
if( err < 0 ) SHOW_RESULT( unlink, err );
 
err = chdir( "/" );
if( err < 0 ) SHOW_RESULT( chdir, err );
err = rmdir( "/bar" );
if( err < 0 ) SHOW_RESULT( rmdir, err );
 
listdir( "/", false );
 
// --------------------------------------------------------------
 
err = mount( "", "/ram", "testfs" );
if( err < 0 ) SHOW_RESULT( mount, err );
 
createfile( "/ram/tinky", 456 );
copyfile( "/ram/tinky", "/ram/laalaa" );
checkfile( "/ram/tinky");
checkfile( "/ram/laalaa");
comparefiles( "/ram/tinky", "/ram/laalaa" );
 
err = chdir( "/ram" );
if( err < 0 ) SHOW_RESULT( chdir, err );
 
createfile( "tinky", 678 );
checkfile( "tinky" );
 
maxfile( "dipsy" );
checkfile( "dipsy" );
copyfile( "dipsy", "po" );
checkfile( "po" );
comparefiles( "dipsy", "po" );
 
testfs_dump();
// --------------------------------------------------------------
err = unlink( "tinky" );
if( err < 0 ) SHOW_RESULT( unlink, err );
 
err = unlink( "dipsy" );
if( err < 0 ) SHOW_RESULT( unlink, err );
 
err = unlink( "po" );
if( err < 0 ) SHOW_RESULT( unlink, err );
err = unlink( "laalaa" );
if( err < 0 ) SHOW_RESULT( unlink, err );
err = chdir( "/" );
if( err < 0 ) SHOW_RESULT( chdir, err );
 
err = umount( "/ram" );
if( err < 0 ) SHOW_RESULT( umount, err );
CYG_TEST_PASS_FINISH("fileio1");
}
 
// -------------------------------------------------------------------------
// EOF fileio1.c
/v2_0/include/inode.h
0,0 → 1,142
#ifndef CYGONCE_IO_FILEIO_INODE_H
#define CYGONCE_IO_FILEIO_INODE_H
//=============================================================================
//
// inode.h
//
// Header describing eCos inodes
//
//=============================================================================
//####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): jlarmour
// Contributors:
// Date: 2002-01-18
// Purpose: Describe inodes
// Description: This header contains the definitions that may be useful to a
// filesystem implementation with the concept of inodes.
// There should remain no *requirement* for a FS to use inodes.
// Instead these are just useful functions and definitions.
//
// Usage:
// #include <cyg/fileio/inode.h>
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <cyg/infra/cyg_type.h>
#include <sys/types.h>
#include <time.h> // time_t
#include <cyg/fileio/fileio.h>
#include <cyg/io/io.h>
#include <limits.h>
 
// some members are named for compatibility for Linux inodes
typedef struct CYG_INODE_TAG {
cyg_uint32 i_ino; // inode number
mode_t i_mode; // mode
nlink_t i_nlink; // number of (hard) links
uid_t i_uid; // UID
gid_t i_gid; // GID
cyg_io_handle_t i_device; // underlying device
off_t i_size; // file size
time_t i_atime; // file access time
time_t i_mtime; // file modification time
time_t i_ctime; // file metadata change time
struct CYG_INODE_TAG *i_parent; // parent inode
 
// these duplicate the contents of a cyg_file, but that's okay
cyg_mtab_entry* i_mte; // mount table entry
struct CYG_FILEOPS_TAG *i_fop; // file operations
 
// inode cache related members
cyg_atomic i_count; // number of references to this inode
struct CYG_INODE_TAG *i_cache_prev; // previous in icache
struct CYG_INODE_TAG *i_cache_next; // next in icache
 
// This allows us to use a GCC extension to extend the size as appropriate
// for individual FS's requirements.
// Obviously anything here cannot be shared between FSs.
CYG_ADDRWORD i_private[];
} cyg_inode;
 
// There should be one cyg_inodecache per FS instance (to preserve inode number
// uniqueness)
typedef void (*cyg_inodecache_freecallback_t)( cyg_inode *);
typedef struct {
cyg_inode *head;
#if CYGNUM_IO_FILEIO_MAX_INODE_CACHE_DEAD > 0
cyg_inode *freeable;
cyg_atomic freeablelistlen;
#endif
cyg_inodecache_freecallback_t freecallback;
size_t privatespace;
// should be some locking eventually
} cyg_inodecache;
 
static __inline__ int
cyg_inodecache_init( cyg_inodecache *ic, size_t extraprivatespace,
cyg_inodecache_freecallback_t freecb )
{
ic->head = NULL;
#if CYGNUM_IO_FILEIO_MAX_INODE_CACHE_DEAD > 0
ic->freeable = NULL;
ic->freeablelistlen = 0;
#endif
ic->privatespace = extraprivatespace;
ic->freecallback = freecb;
return 0;
}
 
// Create an inode, with extra private space. Returns NULL on error.
__externC cyg_inode *
cyg_inode_create( cyg_inodecache *ic );
 
__externC cyg_inode *
cyg_inode_get( cyg_inodecache *ic, cyg_uint32 ino );
 
__externC void
cyg_inode_put( cyg_inodecache *ic, cyg_inode *ino );
 
__externC void
cyg_inodecache_destroy( cyg_inodecache *ic );
 
#endif // CYGONCE_IO_FILEIO_INODE_H
 
// EOF inode.h
/v2_0/include/limits.h
0,0 → 1,67
#ifndef CYGONCE_IO_FILEIO_LIMITS_H
#define CYGONCE_IO_FILEIO_LIMITS_H
/*============================================================================
//
// limits.h
//
// Fileio limits header
//
//============================================================================
//####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): jlarmour
// Contributors:
// Date: 2000-09-11
// Purpose: Provide POSIX limits for file I/O related properties
// Description:
//
// Usage: #include <limits.h>
//
//
//####DESCRIPTIONEND####
//
//==========================================================================*/
 
#include <pkgconf/io_fileio.h>
 
#ifndef __STRICT_ANSI__
# define NAME_MAX 64
# define OPEN_MAX CYGNUM_FILEIO_NFILE
#endif
 
/*--------------------------------------------------------------------------*/
#endif /* ifndef CYGONCE_IO_FILEIO_LIMITS_H */
/* End of fileio.h */
/v2_0/include/dirent.h
0,0 → 1,91
#ifndef CYGONCE_FILEIO_DIRENT_H
#define CYGONCE_FILEIO_DIRENT_H
/*========================================================================
//
// dirent.h
//
// POSIX directory functions
//
//========================================================================
//####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:
// Date: 2000-06-26
// Purpose: This file provides the macros, types and functions
// for directory operations required by POSIX 1003.1.
// Description: Implementations of the types needed for directory
// reading.
// Usage: #include <dirent.h>
//
//####DESCRIPTIONEND####
//
//======================================================================
*/
 
#include <pkgconf/isoinfra.h>
 
#include <sys/types.h>
#include <limits.h>
 
//======================================================================
 
#ifdef __cplusplus
extern "C" {
#endif
 
//======================================================================
// dirent structure.
struct dirent
{
char d_name[NAME_MAX+1];
};
 
//======================================================================
// DIR pointer object.
typedef void *DIR;
 
//======================================================================
#ifdef __cplusplus
} /* extern "C" */
#endif
 
//======================================================================
#endif /* CYGONCE_FILEIO_DIRENT_H multiple inclusion protection */
/* EOF dirent.h */
/v2_0/include/fileio.h
0,0 → 1,430
#ifndef CYGONCE_FILEIO_H
#define CYGONCE_FILEIO_H
//=============================================================================
//
// fileio.h
//
// Fileio header
//
//=============================================================================
//####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 header
// Description: This header contains the external definitions of the general file
// IO subsystem for POSIX and EL/IX compatability.
//
// Usage:
// #include <fileio.h>
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/infra/cyg_type.h>
#include <cyg/hal/hal_tables.h>
 
#include <stddef.h> // NULL, size_t
#include <limits.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
 
//=============================================================================
// forward definitions
 
struct cyg_mtab_entry;
typedef struct cyg_mtab_entry cyg_mtab_entry;
 
struct cyg_fstab_entry;
typedef struct cyg_fstab_entry cyg_fstab_entry;
 
struct CYG_FILEOPS_TAG;
typedef struct CYG_FILEOPS_TAG cyg_fileops;
 
struct CYG_FILE_TAG;
typedef struct CYG_FILE_TAG cyg_file;
 
struct CYG_IOVEC_TAG;
typedef struct CYG_IOVEC_TAG cyg_iovec;
 
struct CYG_UIO_TAG;
typedef struct CYG_UIO_TAG cyg_uio;
 
struct CYG_SELINFO_TAG;
typedef struct CYG_SELINFO_TAG cyg_selinfo;
 
//=============================================================================
// Directory pointer
 
typedef CYG_ADDRWORD cyg_dir;
 
#define CYG_DIR_NULL 0
 
//=============================================================================
// Filesystem table entry
 
typedef int cyg_fsop_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
typedef int cyg_fsop_umount ( cyg_mtab_entry *mte );
typedef int cyg_fsop_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *fte );
typedef int cyg_fsop_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
typedef int cyg_fsop_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
typedef int cyg_fsop_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
typedef int cyg_fsop_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 );
typedef int cyg_fsop_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type );
typedef int cyg_fsop_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *fte );
typedef int cyg_fsop_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out );
typedef int cyg_fsop_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf);
typedef int cyg_fsop_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
typedef int cyg_fsop_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
 
 
struct cyg_fstab_entry
{
const char *name; // filesystem name
CYG_ADDRWORD data; // private data value
cyg_uint32 syncmode; // synchronization mode
cyg_fsop_mount *mount;
cyg_fsop_umount *umount;
cyg_fsop_open *open;
cyg_fsop_unlink *unlink;
cyg_fsop_mkdir *mkdir;
cyg_fsop_rmdir *rmdir;
cyg_fsop_rename *rename;
cyg_fsop_link *link;
cyg_fsop_opendir *opendir;
cyg_fsop_chdir *chdir;
cyg_fsop_stat *stat;
cyg_fsop_getinfo *getinfo;
cyg_fsop_setinfo *setinfo;
} CYG_HAL_TABLE_TYPE;
 
//-----------------------------------------------------------------------------
// Keys for getinfo() and setinfo()
 
#define FS_INFO_CONF 1 /* pathconf() */
#define FS_INFO_ACCESS 2 /* access() */
#define FS_INFO_GETCWD 3 /* getcwd() */
 
//-----------------------------------------------------------------------------
// Types for link()
 
#define CYG_FSLINK_HARD 1 /* form a hard link */
#define CYG_FSLINK_SOFT 2 /* form a soft link */
 
//-----------------------------------------------------------------------------
// getinfo() and setinfo() buffers structures.
 
struct cyg_getcwd_info
{
char *buf; /* buffer for cwd string */
size_t size; /* size of buffer */
};
 
//-----------------------------------------------------------------------------
// Macro to define an initialized fstab entry
 
#define FSTAB_ENTRY( _l, _name, _data, _syncmode, _mount, _umount, \
_open, _unlink, _mkdir, _rmdir, _rename, _link, \
_opendir, _chdir, _stat, _getinfo, _setinfo) \
struct cyg_fstab_entry _l CYG_HAL_TABLE_ENTRY(fstab) = \
{ \
_name, \
_data, \
_syncmode, \
_mount, \
_umount, \
_open, \
_unlink, \
_mkdir, \
_rmdir, \
_rename, \
_link, \
_opendir, \
_chdir, \
_stat, \
_getinfo, \
_setinfo \
};
 
//=============================================================================
// Mount table entry
 
struct cyg_mtab_entry
{
const char *name; // name of mount point
const char *fsname; // name of implementing filesystem
const char *devname; // name of hardware device
CYG_ADDRWORD data; // private data value
// The following are filled in after a successful mount operation
cyg_bool valid; // Valid entry?
cyg_fstab_entry *fs; // pointer to fstab entry
cyg_dir root; // root directory pointer
} CYG_HAL_TABLE_TYPE;
 
 
// This macro defines an initialized mtab entry
 
#define MTAB_ENTRY( _l, _name, _fsname, _devname, _data ) \
struct cyg_mtab_entry _l CYG_HAL_TABLE_ENTRY(mtab) = \
{ \
_name, \
_fsname, \
_devname, \
_data, \
false, \
NULL, \
CYG_DIR_NULL \
};
 
//=============================================================================
// IO vector descriptors
 
struct CYG_IOVEC_TAG
{
void *iov_base; /* Base address. */
ssize_t iov_len; /* Length. */
};
 
enum cyg_uio_rw { UIO_READ, UIO_WRITE };
 
/* Segment flag values. */
enum cyg_uio_seg
{
UIO_USERSPACE, /* from user data space */
UIO_SYSSPACE /* from system space */
};
 
struct CYG_UIO_TAG
{
struct CYG_IOVEC_TAG *uio_iov; /* pointer to array of iovecs */
int uio_iovcnt; /* number of iovecs in array */
off_t uio_offset; /* offset into file this uio corresponds to */
ssize_t uio_resid; /* residual i/o count */
enum cyg_uio_seg uio_segflg; /* see above */
enum cyg_uio_rw uio_rw; /* see above */
};
 
// Limits
#define UIO_SMALLIOV 8 /* 8 on stack, else malloc */
 
//=============================================================================
// Description of open file
 
typedef int cyg_fileop_readwrite (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
typedef cyg_fileop_readwrite cyg_fileop_read;
typedef cyg_fileop_readwrite cyg_fileop_write;
typedef int cyg_fileop_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
typedef int cyg_fileop_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
typedef int cyg_fileop_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
typedef int cyg_fileop_fsync (struct CYG_FILE_TAG *fp, int mode );
typedef int cyg_fileop_close (struct CYG_FILE_TAG *fp);
typedef int cyg_fileop_fstat (struct CYG_FILE_TAG *fp, struct stat *buf );
typedef int cyg_fileop_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
typedef int cyg_fileop_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
 
struct CYG_FILEOPS_TAG
{
cyg_fileop_read *fo_read;
cyg_fileop_write *fo_write;
cyg_fileop_lseek *fo_lseek;
cyg_fileop_ioctl *fo_ioctl;
cyg_fileop_select *fo_select;
cyg_fileop_fsync *fo_fsync;
cyg_fileop_close *fo_close;
cyg_fileop_fstat *fo_fstat;
cyg_fileop_getinfo *fo_getinfo;
cyg_fileop_setinfo *fo_setinfo;
};
 
struct CYG_FILE_TAG
{
cyg_uint32 f_flag; /* file state */
cyg_uint16 f_ucount; /* use count */
cyg_uint16 f_type; /* descriptor type */
cyg_uint32 f_syncmode; /* synchronization protocol */
struct CYG_FILEOPS_TAG *f_ops; /* file operations */
off_t f_offset; /* current offset */
CYG_ADDRWORD f_data; /* file or socket */
CYG_ADDRWORD f_xops; /* extra type specific ops */
cyg_mtab_entry *f_mte; /* mount table entry */
};
 
//-----------------------------------------------------------------------------
// File flags
 
// Allocation here is that bits 0..15 are copies of bits from the open
// flags, bits 16..23 are extra bits that are visible to filesystems but
// are not derived from the open call, and bits 24..31 are reserved for
// the fileio infrastructure.
#define CYG_FREAD O_RDONLY
#define CYG_FWRITE O_WRONLY
#define CYG_FNONBLOCK O_NONBLOCK
#define CYG_FAPPEND O_APPEND
#define CYG_FASYNC 0x00010000
#define CYG_FDIR 0x00020000
 
#define CYG_FLOCKED 0x01000000 // Set if file is locked
#define CYG_FLOCK 0x02000000 // Lock during file ops
#define CYG_FALLOC 0x80000000 // File is "busy", i.e. allocated
 
// Mask for open mode bits stored in file object
#define CYG_FILE_MODE_MASK (CYG_FREAD|CYG_FWRITE|CYG_FNONBLOCK|CYG_FAPPEND)
 
//-----------------------------------------------------------------------------
// Type of file
 
#define CYG_FILE_TYPE_FILE 1 /* file */
#define CYG_FILE_TYPE_SOCKET 2 /* communications endpoint */
#define CYG_FILE_TYPE_DEVICE 3 /* device */
 
//-----------------------------------------------------------------------------
// Keys for getinf() and setinfo()
 
#define FILE_INFO_CONF 1 /* fpathconf() */
 
//-----------------------------------------------------------------------------
// Modes for fsync()
 
#define CYG_FSYNC 1
#define CYG_FDATASYNC 2
 
//-----------------------------------------------------------------------------
// Get/set info buffer structures
 
// This is used for pathconf() and fpathconf()
struct cyg_pathconf_info
{
int name; // POSIX defined variable name
long value; // Returned variable value
};
 
//=============================================================================
// Synchronization modes
// These values are filled into the syncmode fields of the above structures
// and define the synchronization protocol used when accessing the object in
// question.
 
#define CYG_SYNCMODE_NONE (0) // no locking required
 
#define CYG_SYNCMODE_FILE_FILESYSTEM 0x0002 // lock fs during file ops
#define CYG_SYNCMODE_FILE_MOUNTPOINT 0x0004 // lock mte during file ops
#define CYG_SYNCMODE_IO_FILE 0x0010 // lock file during io ops
#define CYG_SYNCMODE_IO_FILESYSTEM 0x0020 // lock fs during io ops
#define CYG_SYNCMODE_IO_MOUNTPOINT 0x0040 // lock mte during io ops
#define CYG_SYNCMODE_SOCK_FILE 0x0100 // lock socket during socket ops
#define CYG_SYNCMODE_SOCK_NETSTACK 0x0800 // lock netstack during socket ops
 
#define CYG_SYNCMODE_IO_SHIFT (4) // shift for IO to file bits
#define CYG_SYNCMODE_SOCK_SHIFT (8) // shift for sock to file bits
 
//=============================================================================
// Mount and umount functions
 
__externC int mount( const char *devname,
const char *dir,
const char *fsname);
 
__externC int umount( const char *name);
 
//=============================================================================
// Select support
 
//-----------------------------------------------------------------------------
// Data structure for embedding in client data structures. A pointer to this
// must be passed to cyg_selrecord() and cyg_selwakeup().
 
struct CYG_SELINFO_TAG
{
CYG_ADDRWORD si_info; // info passed through from fo_select()
CYG_ADDRESS si_thread; // selecting thread pointer
};
 
//-----------------------------------------------------------------------------
// Select support functions.
 
// cyg_selinit() is used to initialize a selinfo structure.
__externC void cyg_selinit( struct CYG_SELINFO_TAG *sip );
 
// cyg_selrecord() is called when a client device needs to register
// the current thread for selection.
__externC void cyg_selrecord( CYG_ADDRWORD info, struct CYG_SELINFO_TAG *sip );
 
// cyg_selwakeup() is called when the client device matches the select
// criterion, and needs to wake up a selector.
__externC void cyg_selwakeup( struct CYG_SELINFO_TAG *sip );
 
//=============================================================================
// Timestamp support
 
// Provides the current time as a time_t timestamp for use in filesystem
// data strucures.
 
__externC time_t cyg_timestamp(void);
 
//=============================================================================
// Default functions.
// Cast to the appropriate type, these functions can be put into any of
// the operation table slots to provide the defined error code.
 
__externC int cyg_fileio_enosys(void);
__externC int cyg_fileio_erofs(void);
__externC int cyg_fileio_enoerr(void);
__externC int cyg_fileio_enotdir(void);
__externC cyg_fileop_select cyg_fileio_seltrue;
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_FILEIO_H
// End of fileio.h
/v2_0/include/sockio.h
0,0 → 1,145
#ifndef CYGONCE_SOCKIO_H
#define CYGONCE_SOCKIO_H
//=============================================================================
//
// sockio.h
//
// Socket IO header
//
//=============================================================================
//####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: Socket IO header
// Description: This header contains the external definitions of the general
// socket IO subsystem for POSIX and EL/IX compatability.
//
// Usage:
// #include <sockio.h>
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/infra/cyg_type.h>
 
#include <stddef.h> // NULL, size_t
#include <limits.h>
#include <sys/types.h>
 
#include <cyg/fileio/fileio.h>
 
//=============================================================================
// Forward definitions
 
struct cyg_nstab_entry;
typedef struct cyg_nstab_entry cyg_nstab_entry;
 
struct cyg_sock_ops;
typedef struct cyg_sock_ops cyg_sock_ops;
 
struct sockaddr;
typedef struct sockaddr sockaddr;
 
struct msghdr;
typedef struct msghdr msghdr;
 
#ifndef CYGPKG_NET
 
typedef cyg_uint32 socklen_t; /* length type for network syscalls */
 
#endif
 
//=============================================================================
// network stack entry
 
struct cyg_nstab_entry
{
cyg_bool valid; // true if stack initialized
cyg_uint32 syncmode; // synchronization protocol
char *name; // stack name
char *devname; // hardware device name
CYG_ADDRWORD data; // private data value
 
int (*init)( cyg_nstab_entry *nste );
int (*socket)( cyg_nstab_entry *nste, int domain, int type,
int protocol, cyg_file *file );
} CYG_HAL_TABLE_TYPE;
 
#define NSTAB_ENTRY( _l, _syncmode, _name, _devname, _data, _init, _socket ) \
struct cyg_nstab_entry _l CYG_HAL_TABLE_ENTRY(nstab) = \
{ \
false, \
_syncmode, \
_name, \
_devname, \
_data, \
_init, \
_socket \
};
 
//=============================================================================
 
struct cyg_sock_ops
{
int (*bind) ( cyg_file *fp, const sockaddr *sa, socklen_t len );
int (*connect) ( cyg_file *fp, const sockaddr *sa, socklen_t len );
int (*accept) ( cyg_file *fp, cyg_file *new_fp,
struct sockaddr *name, socklen_t *anamelen );
int (*listen) ( cyg_file *fp, int len );
int (*getname) ( cyg_file *fp, sockaddr *sa, socklen_t *len, int peer );
int (*shutdown) ( cyg_file *fp, int flags );
int (*getsockopt)( cyg_file *fp, int level, int optname,
void *optval, socklen_t *optlen);
int (*setsockopt)( cyg_file *fp, int level, int optname,
const void *optval, socklen_t optlen);
int (*sendmsg) ( cyg_file *fp, const struct msghdr *m,
int flags, ssize_t *retsize );
int (*recvmsg) ( cyg_file *fp, struct msghdr *m,
socklen_t *namelen, ssize_t *retsize );
};
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_SOCKIO_H
// End of sockio.h
/v2_0/doc/fileio.txt
0,0 → 1,593
File System Support Infrastructure
==================================
 
Nick Garnett
v0.2
 
 
This document describes the filesystem infrastructure provided in
eCos. This is implemented by the FILEIO package and provides POSIX
compliant file and IO operations together with the BSD socket
API. These APIs are described in the relevant standards and original
documentation and will not be described here. This document is,
instead, concerned with the interfaces presented to client
filesystems and network protocol stacks.
 
The FILEIO infrastructure consist mainly of a set of tables containing
pointers to the primary interface functions of a file system. This
approach avoids problems of namespace pollution (several filesystems
can have a function called read(),so long as they are static). The
system is also structured to eliminate the need for dynamic memory
allocation.
 
New filesystems can be written directly to the interfaces described
here. Existing filesystems can be ported very easily by the
introduction of a thin veneer porting layer that translates FILEIO
calls into native filesystem calls.
 
The term filesystem should be read fairly loosely in this
document. Object accessed through these interfaces could equally be
network protocol sockets, device drivers, fifos, message queues or any
other object that can present a file-like interface.
 
File System Table
-----------------
 
The filesystem table is an array of entries that describe each
filesystem implementation that is part of the system image. Each
resident filesystem should export an entry to this table using the
FSTAB_ENTRY() macro.
 
The table entries are described by the following structure:
 
struct cyg_fstab_entry
{
const char *name; // filesystem name
CYG_ADDRWORD data; // private data value
cyg_uint32 syncmode; // synchronization mode
int (*mount) ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
int (*umount) ( cyg_mtab_entry *mte );
int (*open) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *fte );
int (*unlink) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
int (*mkdir) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
int (*rmdir) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
int (*rename) ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 );
int (*link) ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type );
int (*opendir) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *fte );
int (*chdir) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out );
int (*stat) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf);
int (*getinfo) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, char *buf, int len );
int (*setinfo) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, char *buf, int len );
};
 
The _name_ field points to a string that identifies this filesystem
implementation. Typical values might be "romfs", "msdos", "ext2" etc.
 
The _data_ field contains any private data that the filesystem needs,
perhaps the root of its data structures.
 
The _syncmode_ field contains a description of the locking protocol to
be used when accessing this filesystem. It will be described in more
detail in the "Synchronization" section.
 
The remaining fields are pointers to functions that implement
filesystem operations that apply to files and directories as whole
objects. The operation implemented by each function should be obvious
from the names, with a few exceptions.
 
The _opendir_ function opens a directory for reading. See the section
on Directories later for details.
 
The _getinfo_ and _setinfo_ functions provide support for various
minor control and information functions such as pathconf() and
access().
 
With the exception of the _mount_ and _umount_ functions, all of these
functions take three standard arguments, a pointer to a mount table
entry (see later) a directory pointer (also see later) and a file name
relative to the directory. These should be used by the filesystem to
locate the object of interest.
 
Mount Table
-----------
 
The mount table records the filesystems that are actually active.
These can be seen as being analogous to mount points in Unix systems.
 
There are two sources of mount table entries. Filesystems (or other
components) may export static entries to the table using the
MTAB_ENTRY() macro. Alternatively, new entries may be installed at run
time using the mount() function. Both types of entry may be unmounted
with the umount() function.
 
A mount table entry has the following structure:
 
struct cyg_mtab_entry
{
const char *name; // name of mount point
const char *fsname; // name of implementing filesystem
const char *devname; // name of hardware device
CYG_ADDRWORD data; // private data value
cyg_bool valid; // Valid entry?
cyg_fstab_entry *fs; // pointer to fstab entry
cyg_dir root; // root directory pointer
};
 
The _name_ field identifies the mount point. This is used to translate
rooted filenames (filenames that begin with "/") into the correct
filesystem. When a file name that begins with "/" is submitted, it is
matched against the _name_ fields of all valid mount table
entries. The entry that yields the longest match terminating before a
"/", or end of string, wins and the appropriate function from the
filesystem table entry is then passed the remainder of the file name
together with a pointer to the table entry and the value of the _root_
field as the directory pointer.
 
For example, consider a mount table that contains the following
entries:
 
{ "/", "msdos", "/dev/hd0", ... }
{ "/fd", "msdos", "/dev/fd0", ... }
{ "/rom", "romfs", "", ... }
{ "/tmp", "ramfs", "", ... }
{ "/dev", "devfs", "", ... }
 
An attempt to open "/tmp/foo" would be directed to the RAM filesystem
while an open of "/bar/bundy" would be directed to the hard disc MSDOS
filesystem. Opening "/dev/tty0" would be directed to the device
management filesystem for lookup in the device table.
 
Unrooted file names (those that do not begin with a '/') are passed
straight to the current directory. The current directory is
represented by a pair consisting of a mount table entry and a
directory pointer.
 
The _fsname_ field points to a string that should match the _name_
field of the implementing filesystem. During initialization the mount
table is scanned and the _fsname_ entries looked up in the
filesystem table. For each match, the filesystem's _mount_ function
is called and if successful the mount table entry is marked as valid
and the _fs_ pointer installed.
 
The _devname_ field contains the name of the device that this
filesystem is to use. This may match an entry in the device table (see
later) or may be a string that is specific to the filesystem if it has
its own internal device drivers.
 
The _data_ field is a private data value. This may be installed either
statically when the table entry is defined, or may be installed during
the _mount_ operation.
 
The _valid_ field indicates whether this mount point has actually been
mounted successfully. Entries with a false _valid_ field are ignored
when searching for a name match.
 
The _fs_ field is installed after a successful mount operation to
point to the implementing filesystem.
 
The _root_ field contains a directory pointer value that the
filesystem can interpret as the root of its directory tree. This is
passed as the _dir_ argument of filesystem functions that operate on
rooted filenames. This field must be initialized by the filesystem's
_mount_ function.
 
 
 
File Table
----------
 
Once a file has been opened it is represented by an open file
object. These are allocated from an array of available file
objects. User code accesses these open file objects via a second array
of pointers which is indexed by small integer offsets. This gives the
usual Unix file descriptor functionality, complete with the various
duplication mechanisms.
 
A file table entry has the following structure:
 
struct CYG_FILE_TAG
{
cyg_uint32 f_flag; /* file state */
cyg_uint16 f_ucount; /* use count */
cyg_uint16 f_type; /* descriptor type */
cyg_uint32 f_syncmode; /* synchronization protocol */
struct CYG_FILEOPS_TAG *f_ops; /* file operations */
off_t f_offset; /* current offset */
CYG_ADDRWORD f_data; /* file or socket */
CYG_ADDRWORD f_xops; /* extra type specific ops */
cyg_mtab_entry *f_mte; /* mount table entry */
};
 
The _f_flag_ field contains some FILEIO control bits and some of the
bits from the open call (defined by CYG_FILE_MODE_MASK).
 
The _f_ucount_ field contains a use count that controls when a file
will be closed. Each duplicate in the file descriptor array counts for
one reference here and it is also incremented around each I/O
operation.
 
The _f_type_ field indicates the type of the underlying file
object. Some of the possible values here are CYG_FILE_TYPE_FILE,
CYG_FILE_TYPE_SOCKET or CYG_FILE_TYPE_DEVICE.
 
The _f_syncmode_ field is copied from the _syncmode_ field of the
implementing filesystem. Its use is described in the "Synchronization"
section later.
 
The _f_offset_ field records the current file position. It is the
responsibility of the file operation functions to keep this field up
to date.
 
The _f_data_ field contains private data placed here by the underlying
filesystem. Normally this will be a pointer to or handle on the
filesystem object that implements this file.
 
The _f_xops_ field contains a pointer to any extra type specific
operation functions. For example, the socket I/O system installs a
pointer to a table of functions that implement the standard socket
operations.
 
The _f_mte_ field contains a pointer to the parent mount table entry
for this file. It is used mainly to implement the synchronization
protocol. This may contain a pointer to some other data structure in
file objects not derived from a filesystem.
 
The _f_ops_ field contains a pointer to a table of file I/O
operations. This has the following structure:
 
struct CYG_FILEOPS_TAG
{
int (*fo_read) (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
int (*fo_write) (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
int (*fo_lseek) (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
int (*fo_ioctl) (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
int (*fo_select) (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
int (*fo_fsync) (struct CYG_FILE_TAG *fp, int mode );
int (*fo_close) (struct CYG_FILE_TAG *fp);
int (*fo_fstat) (struct CYG_FILE_TAG *fp, struct stat *buf );
int (*fo_getinfo) (struct CYG_FILE_TAG *fp, int key, char *buf, int len );
int (*fo_setinfo) (struct CYG_FILE_TAG *fp, int key, char *buf, int len );
};
 
It should be obvious from the names of most of these functions what
their responsibilities are. The _fo_getinfo_ and _fo_setinfo_
function, like their counterparts in the filesystem structure,
implement minor control and info functions such as fpathconf().
 
The second argument to _fo_read_ and _fo_write_ is a pointer to a UIO
structure:
 
struct CYG_UIO_TAG
{
struct CYG_IOVEC_TAG *uio_iov; /* pointer to array of iovecs */
int uio_iovcnt; /* number of iovecs in array */
off_t uio_offset; /* offset into file this uio corresponds to */
ssize_t uio_resid; /* residual i/o count */
enum cyg_uio_seg uio_segflg; /* see above */
enum cyg_uio_rw uio_rw; /* see above */
};
 
struct CYG_IOVEC_TAG
{
void *iov_base; /* Base address. */
ssize_t iov_len; /* Length. */
};
 
This structure encapsulates the parameters of any data transfer
operation. It provides support for scatter/gather operations and
records the progress of any data transfer. It is also compatible with
the I/O operations of any BSD-derived network stacks and filesystems.
 
 
When a file is opened (or a file object created by some other means,
such as socket() or accept()) it is the responsibility of the
filesystem open operation to initialize all the fields of the object
except the _f_ucount_, _f_syncmode_ and _f_mte_ fields. Since the
_f_flag_ field will already contain bits belonging to the FILEIO
infrastructure, any changes to it must be made with the appropriate
logical operations.
 
 
Directories
-----------
 
Filesystem operations all take a directory pointer as one of their
arguments. A directory pointer is an opaque handle managed by the
filesystem. It should encapsulate a reference to a specific directory
within the filesystem. For example, it may be a pointer to the data
structure that represents that directory, or a pointer to a pathname
for the directory.
 
The _chdir_ filesystem function has two modes of use. When passed a
pointer in the _dir_out_ argument, it should locate the named
directory and place a directory pointer there. If the _dir_out_
argument is NULL then the _dir_ argument is a previously generated
directory pointer that can now be disposed of. When the infrastructure
is implementing the chdir() function it makes two calls to filesystem
_chdir_ functions. The first is to get a directory pointer for the new
current directory. If this succeeds the second is to dispose of the
old current directory pointer.
 
The _opendir_ function is used to open a directory for reading. This
results in an open file object that can be read to return a sequence
of _struct dirent_ objects. The only operation that are allowed on
this file are _read_, _lseek_ and _close_. Each read operation on this
file should return a single _struct dirent_ object. When the end of
the directory is reached, zero should be returned. The only seek
operation allowed is a rewind to the start of the directory, by
supplying an offset of zero and a _whence_ specifier of _SEEK_SET_.
 
Most of these considerations are invisible to clients of a filesystem
since they will access directories via the POSIX
opendir()/readdir()/closedir() functions.
 
Support for the _getcwd()_ function is provided by three mechanisms.
The first is to use the _FS_INFO_GETCWD_ getinfo key on the filesystem
to use any internal support that it has for this. If that fails it
falls back on one of the two other mechanisms. If
_CYGPKG_IO_FILEIO_TRACK_CWD_ is set then the current directory is
tracked textually in chdir() and the result of that is reported in
getcwd(). Otherwise an attempt is made to traverse the directory tree
to its root using ".." entries.
 
This last option is complicated and expensive, and relies on the
filesystem supporting "." and ".." entries. This is not always the
case, particularly if the filesystem has been ported from a
non-UNIX-compatible source. Tracking the pathname textually will
usually work, but might not produce optimum results when symbolic
links are being used.
 
 
Synchronization
---------------
 
The FILEIO infrastructure provides a synchronization mechanism for
controlling concurrent access to filesystems. This allows existing
filesystems to be ported to eCos, even if they do not have their own
synchronization mechanisms. It also allows new filesystems to be
implemented easily without having to consider the synchronization
issues.
 
The infrastructure maintains a mutex for each entry in each of
the main tables: filesystem table, mount table and file table. For
each class of operation each of these mutexes may be locked before the
corresponding filesystem operation is invoked.
 
The synchronization protocol implemented by a filesystem is described
by the _syncmode_ field of the filesystem table entry. This is a
combination of the following flags:
 
CYG_SYNCMODE_FILE_FILESYSTEM Lock the filesystem table entry mutex
during all filesystem level operations.
 
CYG_SYNCMODE_FILE_MOUNTPOINT Lock the mount table entry mutex
during all filesystem level operations.
 
CYG_SYNCMODE_IO_FILE Lock the file table entry mutex during all
I/O operations.
 
CYG_SYNCMODE_IO_FILESYSTEM Lock the filesystem table entry mutex
during all I/O operations.
CYG_SYNCMODE_IO_MOUNTPOINT Lock the mount table entry mutex during
all I/O operations.
 
CYG_SYNCMODE_SOCK_FILE Lock the file table entry mutex during
all socket operations.
 
CYG_SYNCMODE_SOCK_NETSTACK Lock the network stack table entry mutex
during all socket operations.
 
CYG_SYNCMODE_NONE Perform no locking at all during any
operations.
 
 
The value of the _syncmode_ in the filesystem table entry will be
copied by the infrastructure to the open file object after a
successful open() operation.
 
 
Initialization and Mounting
---------------------------
 
As mentioned previously, mount table entries can be sourced from two
places. Static entries may be defined by using the MTAB_ENTRY()
macro. Such entries will be automatically mounted on system startup.
For each entry in the mount table that has a non-null _name_ field the
filesystem table is searched for a match with the _fsname_ field. If a
match is found the filesystem's _mount_ entry is called and if
successful the mount table entry marked valid and the _fs_ field
initialized. The _mount_ function is responsible for initializing the
_root_ field.
 
The size of the mount table is defined by the configuration value
CYGNUM_FILEIO_MTAB_MAX. Any entries that have not been statically
defined are available for use by dynamic mounts.
 
A filesystem may be mounted dynamically by calling mount(). This
function has the following prototype:
 
int mount( const char *devname,
const char *dir,
const char *fsname);
 
The _devname_ argument identifies a device that will be used by this
filesystem and will be assigned to the _devname_ field of the mount
table entry.
 
The _dir_ argument is the mount point name, it will be assigned to the
_name_ field of the mount table entry.
 
The _fsname_ argument is the name of the implementing filesystem, it
will be assigned to the _fsname_ entry of the mount table entry.
 
The process of mounting a filesystem dynamically is as follows. First
a search is made of the mount table for an entry with a NULL _name_
field to be used for the new mount point. The filesystem table is then
searched for an entry whose name matches _fsname_. If this is
successful then the mount table entry is initialized and the
filesystem's _mount_ operation called. If this is successful, the
mount table entry is marked valid and the _fs_ field initialized.
 
Unmounting a filesystem is done by the umount() function. This can
unmount filesystems whether they were mounted statically or
dynamically.
 
The umount() function has the following prototype:
 
int umount( const char *name );
 
The mount table is searched for a match between the _name_ argument
and the entry _name_ field. When a match is found the filesystem's
_umount_ operation is called and if successful, the mount table entry
is invalidated by setting its _valid_ field false and the _name_ field
to NULL.
 
Sockets
-------
 
If a network stack is present, then the FILEIO infrastructure also
provides access to the standard BSD socket calls.
 
The netstack table contains entries which describe the network
protocol stacks that are in the system image. Each resident stack
should export an entry to this table using the NSTAB_ENTRY() macro.
 
Each table entry has the following structure:
 
struct cyg_nstab_entry
{
cyg_bool valid; // true if stack initialized
cyg_uint32 syncmode; // synchronization protocol
char *name; // stack name
char *devname; // hardware device name
CYG_ADDRWORD data; // private data value
 
int (*init)( cyg_nstab_entry *nste );
int (*socket)( cyg_nstab_entry *nste, int domain, int type,
int protocol, cyg_file *file );
};
 
This table is analogous to a combination of the filesystem and mount
tables.
 
The _valid_ field is set true if the stack's _init_ function returned
successfully and the _syncmode_ field contains the CYG_SYNCMODE_SOCK_*
bits described above.
 
The _name_ field contains the name of the protocol stack.
 
The _devname_ field names the device that the stack is using. This may
reference a device under "/dev", or may be a name that is only
meaningful to the stack itself.
 
The _init_ function is called during system initialization to start
the protocol stack running. If it returns non-zero the _valid_ field
is set false and the stack will be ignored subsequently.
 
The _socket_ function is called to attempt to create a socket in the
stack. When the socket() API function is called the netstack table is
scanned and for each valid entry the _socket_ function is called. If
this returns non-zero then the scan continues to the next valid stack,
or terminates with an error if the end of the table is reached.
 
The result of a successful socket call is an initialized file object
with the _f_xops_ field pointing to the following structure:
 
struct cyg_sock_ops
{
int (*bind) ( cyg_file *fp, const sockaddr *sa, socklen_t len );
int (*connect) ( cyg_file *fp, const sockaddr *sa, socklen_t len );
int (*accept) ( cyg_file *fp, cyg_file *new_fp,
struct sockaddr *name, socklen_t *anamelen );
int (*listen) ( cyg_file *fp, int len );
int (*getname) ( cyg_file *fp, sockaddr *sa, socklen_t *len, int peer );
int (*shutdown) ( cyg_file *fp, int flags );
int (*getsockopt)( cyg_file *fp, int level, int optname,
void *optval, socklen_t *optlen);
int (*setsockopt)( cyg_file *fp, int level, int optname,
const void *optval, socklen_t optlen);
int (*sendmsg) ( cyg_file *fp, const struct msghdr *m,
int flags, ssize_t *retsize );
int (*recvmsg) ( cyg_file *fp, struct msghdr *m,
socklen_t *namelen, ssize_t *retsize );
};
 
It should be obvious from the names of these functions which API calls
they provide support for. The _getname_ function provides support for
both getsockname() and getpeername() while the _sendmsg_ and _recvmsg_
functions provide support for send(), sendto(), sendmsg(), recv(),
recvfrom() and recvmsg() as appropriate.
 
 
 
Select
------
 
The infrastructure provides support for implementing a select
mechanism. This is modeled on the mechanism in the BSD kernel, but has
been modified to make it implementation independent.
 
The main part of the mechanism is the select() API call. This
processes its arguments and calls the _fo_select_ function on all file
objects referenced by the file descriptor sets passed to it. If the
same descriptor appears in more than one descriptor set, the
_fo_select_ function will be called separately for each appearance.
 
The _which_ argument of the _fo_select_ function will either be
CYG_FREAD to test for read conditions, CYG_FWRITE to test for write
conditions or zero to test for exceptions. For each of these options
the function should test whether the condition is satisfied and if so
return true. If it is not satisfied then it should call
cyg_selrecord() with the _info_ argument that was passed to the
function and a pointer to a cyg_selinfo structure.
 
The cyg_selinfo structure is used to record information about current
select operations. Any object that needs to support select must
contain an instance of this structure. Separate cyg_selinfo
structures should be kept for each of the options that the object can
select on - read, write or exception.
 
If none of the file objects report that the select condition is
satisfied, then the select() API function puts the calling thread to
sleep waiting either for a condition to become satisfied, or for the
optional timeout to expire.
 
A selectable object must have some asynchronous activity that may
cause a select condition to become true - either via interrupts or the
activities of other threads. Whenever a selectable condition is
satisfied, the object should call cyg_selwakeup() with a pointer to
the appropriate cyg_selinfo structure. If the thread is still waiting,
this will cause it to wake up and repeat its poll of the file
descriptors. This time around, the object that caused the wakeup
should indicate that the select condition is satisfied, and the
_select()_ API call will return.
 
Note that _select()_ does not exhibit real time behaviour: the
iterative poll of the descriptors, and the wakeup mechanism mitigate
against this. If real time response to device or socket I/O is
required then separate threads should be devoted to each device of
interest.
 
 
Devices
-------
 
Devices are accessed by means of a pseudo-filesystem, "devfs", that is
mounted on "/dev". Open operations are translated into calls to
cyg_io_lookup() and if successful result in a file object whose
_f_ops_ functions translate filesystem API functions into calls into
the device API.
 
// EOF fileio.txt
/v2_0/doc/fileio.sgml
0,0 → 1,1196
<!-- {{{ Banner -->
 
<!-- =============================================================== -->
<!-- -->
<!-- fileio.sgml -->
<!-- -->
<!-- eCos Generic File I/O package documentation -->
<!-- -->
<!-- =============================================================== -->
<!-- ####COPYRIGHTBEGIN#### -->
<!-- -->
<!-- =============================================================== -->
<!-- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -->
<!-- This material may be distributed only subject to the terms -->
<!-- and conditions set forth in the Open Publication License, v1.0 -->
<!-- or later (the latest version is presently available at -->
<!-- http://www.opencontent.org/openpub/) -->
<!-- Distribution of the work or derivative of the work in any -->
<!-- standard (paper) book form is prohibited unless prior -->
<!-- permission obtained from the copyright holder -->
<!-- =============================================================== -->
<!-- -->
<!-- ####COPYRIGHTEND#### -->
<!-- =============================================================== -->
<!-- #####DESCRIPTIONBEGIN#### -->
<!-- -->
<!-- ####DESCRIPTIONEND#### -->
<!-- =============================================================== -->
 
<!-- }}} -->
 
<part id="fileio">
<title>File System Support Infrastructure</title>
 
<!-- {{{ Introduction -->
 
<chapter id="fileio-intro">
<title>Introduction</title>
 
<para>
This document describes the filesystem infrastructure provided in
eCos. This is implemented by the FILEIO package and provides POSIX
compliant file and IO operations together with the BSD socket
API. These APIs are described in the relevant standards and original
documentation and will not be described here. See <xref
linkend="posix-standard-support"> for details of which parts of the
POSIX standard are supported.
</para>
 
<para>
This document is concerned with the interfaces presented to client
filesystems and network protocol stacks.
</para>
 
<para>
The FILEIO infrastructure consist mainly of a set of tables containing
pointers to the primary interface functions of a file system. This
approach avoids problems of namespace pollution (for example several
filesystems can have a function called <function>read()</function>, so long as they are
static). The system is also structured to eliminate the need for
dynamic memory allocation.
</para>
 
<para>
New filesystems can be written directly to the interfaces described
here. Existing filesystems can be ported very easily by the
introduction of a thin veneer porting layer that translates FILEIO
calls into native filesystem calls.
</para>
 
<para>
The term filesystem should be read fairly loosely in this
document. Object accessed through these interfaces could equally be
network protocol sockets, device drivers, fifos, message queues or any
other object that can present a file-like interface.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ File System Table -->
 
<chapter id="fileio-fstab">
<title>File System Table</title>
 
<para>
The filesystem table is an array of entries that describe each
filesystem implementation that is part of the system image. Each
resident filesystem should export an entry to this table using the
<literal>FSTAB_ENTRY()</literal> macro.
</para>
 
<note>
<title>Note</title>
<para>
At present we do not support dynamic addition or removal of table
entries. However, an API similar to <function>mount()</function> would
allow new entries to be added to the table.
</para>
</note>
 
<para>
The table entries are described by the following structure:
</para>
 
<programlisting>
struct cyg_fstab_entry
{
const char *name; // filesystem name
CYG_ADDRWORD data; // private data value
cyg_uint32 syncmode; // synchronization mode
int (*mount) ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
int (*umount) ( cyg_mtab_entry *mte );
int (*open) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *fte );
int (*unlink) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
int (*mkdir) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
int (*rmdir) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
int (*rename) ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 );
int (*link) ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type );
int (*opendir) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *fte );
int (*chdir) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out );
int (*stat) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf);
int (*getinfo) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, char *buf, int len );
int (*setinfo) ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, char *buf, int len );
};
</programlisting>
 
<para>
The <structfield>name</structfield> field points to a string that
identifies this filesystem implementation. Typical values might be
&quot;romfs&quot;, &quot;msdos&quot;, &quot;ext2&quot; etc.
</para>
 
<para>
The <structfield>data</structfield> field contains any private data
that the filesystem needs, perhaps the root of its data structures.
</para>
 
<para>
The <structfield>syncmode</structfield> field contains a description of
the locking protocol to be used when accessing this filesystem. It
will be described in more detail in <xref linkend="fileio-synchronization">.
</para>
 
<para>
The remaining fields are pointers to functions that implement
filesystem operations that apply to files and directories as whole
objects. The operation implemented by each function should be obvious
from the names, with a few exceptions:
</para>
 
<para>
The <function>opendir()</function> function pointer opens a directory
for reading. See <xref linkend="fileio-directories"> for details.
</para>
 
<para>
The <function>getinfo()</function> and
<function>setinfo()</function> function pointers provide support for
various minor control and information functions such as
<function>pathconf()</function> and <function>access()</function>.
</para>
 
<para>
With the exception of the <function>mount()</function> and
<function>umount()</function> functions, all of these functions
take three standard arguments, a pointer to a mount table entry (see
later) a directory pointer (also see later) and a file name relative
to the directory. These should be used by the filesystem to locate the
object of interest.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ Mount Table -->
 
<chapter id="fileio-mount-table">
<title>Mount Table</title>
 
<para>
The mount table records the filesystems that are actually active.
These can be seen as being analogous to mount points in Unix systems.
</para>
 
<para>
There are two sources of mount table entries. Filesystems (or other
components) may export static entries to the table using the
<literal>MTAB_ENTRY()</literal> macro. Alternatively, new entries may
be installed at run time using the <function>mount()</function>
function. Both types of entry may be unmounted with the
<function>umount()</function> function.
</para>
 
<para>
A mount table entry has the following structure:
</para>
 
<programlisting>
struct cyg_mtab_entry
{
const char *name; // name of mount point
const char *fsname; // name of implementing filesystem
const char *devname; // name of hardware device
CYG_ADDRWORD data; // private data value
cyg_bool valid; // Valid entry?
cyg_fstab_entry *fs; // pointer to fstab entry
cyg_dir root; // root directory pointer
};
</programlisting>
 
<para>
The <structfield>name</structfield> field identifies the mount
point. This is used to direct rooted filenames (filenames that
begin with &quot;/&quot;) to the correct filesystem. When a file
name that begins with &quot;/&quot; is submitted, it is matched
against the <structfield>name</structfield> fields of all valid mount
table entries. The entry that yields the longest match terminating
before a &quot;/&quot;, or end of string, wins and the appropriate
function from the filesystem table entry is then passed the remainder
of the file name together with a pointer to the table entry and the
value of the <structfield>root</structfield> field as the directory
pointer.
</para>
 
<para>
For example, consider a mount table that contains the following
entries:
</para>
 
<programlisting>
{ "/", "msdos", "/dev/hd0", ... }
{ "/fd", "msdos", "/dev/fd0", ... }
{ "/rom", "romfs", "", ... }
{ "/tmp", "ramfs", "", ... }
{ "/dev", "devfs", "", ... }
</programlisting>
 
<para>
An attempt to open &quot;/tmp/foo&quot; would be directed to the RAM
filesystem while an open of &quot;/bar/bundy&quot; would be directed
to the hard disc MSDOS filesystem. Opening &quot;/dev/tty0&quot; would
be directed to the device management filesystem for lookup in the
device table.
</para>
 
<para>
Unrooted file names (those that do not begin with a '/') are passed
straight to the filesystem that contains the current directory. The
current directory is represented by a pair consisting of a mount table
entry and a directory pointer.
</para>
 
<para>
The <structfield>fsname</structfield> field points to a string that
should match the <structfield>name</structfield> field of the
implementing filesystem. During initialization the mount table is
scanned and the <structfield>fsname</structfield> entries looked up in
the filesystem table. For each match, the filesystem's _mount_
function is called and if successful the mount table entry is marked
as valid and the <structfield>fs</structfield> pointer installed.
</para>
 
<para>
The <structfield>devname</structfield> field contains the name of the
device that this filesystem is to use. This may match an entry in the
device table (see later) or may be a string that is specific to the
filesystem if it has its own internal device drivers.
</para>
 
<para>
The <structfield>data</structfield> field is a private data value. This
may be installed either statically when the table entry is defined, or
may be installed during the <function>mount()</function> operation.
</para>
 
<para>
The <structfield>valid</structfield> field indicates whether this mount
point has actually been mounted successfully. Entries with a false
<structfield>valid</structfield> field are ignored when searching for a
name match.
</para>
 
<para>
The <structfield>fs</structfield> field is installed after a successful
<function>mount()</function> operation to point to the implementing
filesystem.
</para>
 
<para>
The <structfield>root</structfield> field contains a directory pointer
value that the filesystem can interpret as the root of its directory
tree. This is passed as the <parameter>dir</parameter> argument of
filesystem functions that operate on rooted filenames. This field must
be initialized by the filesystem's <function>mount()</function>
function.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ File Table -->
 
<chapter id="fileio-file-table">
<title>File Table</title>
 
<para>
Once a file has been opened it is represented by an open file
object. These are allocated from an array of available file
objects. User code accesses these open file objects via a second array
of pointers which is indexed by small integer offsets. This gives the
usual Unix file descriptor functionality, complete with the various
duplication mechanisms.
</para>
 
<para>
A file table entry has the following structure:
</para>
 
<programlisting>
struct CYG_FILE_TAG
{
cyg_uint32 f_flag; /* file state */
cyg_uint16 f_ucount; /* use count */
cyg_uint16 f_type; /* descriptor type */
cyg_uint32 f_syncmode; /* synchronization protocol */
struct CYG_FILEOPS_TAG *f_ops; /* file operations */
off_t f_offset; /* current offset */
CYG_ADDRWORD f_data; /* file or socket */
CYG_ADDRWORD f_xops; /* extra type specific ops */
cyg_mtab_entry *f_mte; /* mount table entry */
};
</programlisting>
 
<para>
The <structfield>f_flag</structfield> field contains some FILEIO
control bits and some bits propagated from the
<parameter>flags</parameter> argument of the
<function>open()</function> call (defined by
<literal>CYG_FILE_MODE_MASK</literal>).
</para>
 
<para>
The <structfield>f_ucount</structfield> field contains a use count that
controls when a file will be closed. Each duplicate in the file
descriptor array counts for one reference here. It is also
incremented around each I/O operation to ensure that the file cannot
be closed while it has current I/O operations.
</para>
 
<para>
The <structfield>f_type</structfield> field indicates the type of the
underlying file object. Some of the possible values here are
<literal>CYG_FILE_TYPE_FILE</literal>,
<literal>CYG_FILE_TYPE_SOCKET</literal> or <literal>CYG_FILE_TYPE_DEVICE</literal>.
</para>
 
<para>
The <structfield>f_syncmode</structfield> field is copied from the
<structfield>syncmode</structfield> field of the implementing
filesystem. Its use is described in <xref linkend="fileio-synchronization">.
</para>
 
<para>
The <structfield>f_offset</structfield> field records the current file
position. It is the responsibility of the file operation functions to
keep this field up to date.
</para>
 
<para>
The <structfield>f_data</structfield> field contains private data
placed here by the underlying filesystem. Normally this will be a
pointer to, or handle on, the filesystem object that implements this
file.
</para>
 
<para>
The <structfield>f_xops</structfield> field contains a pointer to any
extra type specific operation functions. For example, the socket I/O
system installs a pointer to a table of functions that implement the
standard socket operations.
</para>
 
<para>
The <structfield>f_mte</structfield> field contains a pointer to the
parent mount table entry for this file. It is used mainly to implement
the synchronization protocol. This may contain a pointer to some other
data structure in file objects not derived from a filesystem.
</para>
 
<para>
The <structfield>f_ops</structfield> field contains a pointer to a
table of file I/O operations. This has the following structure:
</para>
 
<programlisting>
struct CYG_FILEOPS_TAG
{
int (*fo_read) (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
int (*fo_write) (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
int (*fo_lseek) (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
int (*fo_ioctl) (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
int (*fo_select) (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
int (*fo_fsync) (struct CYG_FILE_TAG *fp, int mode );
int (*fo_close) (struct CYG_FILE_TAG *fp);
int (*fo_fstat) (struct CYG_FILE_TAG *fp, struct stat *buf );
int (*fo_getinfo) (struct CYG_FILE_TAG *fp, int key, char *buf, int len );
int (*fo_setinfo) (struct CYG_FILE_TAG *fp, int key, char *buf, int len );
};
</programlisting>
 
<para>
It should be obvious from the names of most of these functions what
their responsibilities are. The <function>fo_getinfo()</function>
and <function>fo_setinfo()</function> function pointers, like their
counterparts in the filesystem structure, implement minor control and
info functions such as <function>fpathconf()</function>.
</para>
 
<para>
The second argument to the <function>fo_read()</function> and
<function>fo_write()</function> function pointers is a pointer to a
UIO structure:
</para>
 
<programlisting>
struct CYG_UIO_TAG
{
struct CYG_IOVEC_TAG *uio_iov; /* pointer to array of iovecs */
int uio_iovcnt; /* number of iovecs in array */
off_t uio_offset; /* offset into file this uio corresponds to */
ssize_t uio_resid; /* residual i/o count */
enum cyg_uio_seg uio_segflg; /* see above */
enum cyg_uio_rw uio_rw; /* see above */
};
 
struct CYG_IOVEC_TAG
{
void *iov_base; /* Base address. */
ssize_t iov_len; /* Length. */
};
</programlisting>
 
<para>
This structure encapsulates the parameters of any data transfer
operation. It provides support for scatter/gather operations and
records the progress of any data transfer. It is also compatible with
the I/O operations of any BSD-derived network stacks and filesystems.
</para>
 
<para>
When a file is opened (or a file object created by some other means,
such as <function>socket()</function> or <function>accept()</function>) it is the
responsibility of the filesystem open operation to initialize all the
fields of the object except the <structfield>f_ucount</structfield>,
<structfield>f_syncmode</structfield> and
<structfield>f_mte</structfield> fields. Since the
<structfield>f_flag</structfield> field will already contain bits belonging to the FILEIO
infrastructure, any changes to it must be made with the appropriate
logical operations.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ Directories -->
 
<chapter id="fileio-directories">
<title>Directories</title>
 
<para>
Filesystem operations all take a directory pointer as one of their
arguments. A directory pointer is an opaque handle managed by the
filesystem. It should encapsulate a reference to a specific directory
within the filesystem. For example, it may be a pointer to the data
structure that represents that directory (such as an inode), or a
pointer to a pathname for the directory.
</para>
 
<para>
The <function>chdir()</function> filesystem function pointer has two
modes of use. When passed a pointer in the
<parameter>dir_out</parameter> argument, it should locate the named
directory and place a directory pointer there. If the
<parameter>dir_out</parameter> argument is NULL then the
<parameter>dir</parameter> argument is a previously generated
directory pointer that can now be disposed of. When the infrastructure
is implementing the <function>chdir()</function> function it makes two
calls to filesystem <function>chdir()</function> functions. The first
is to get a directory pointer for the new current directory. If this
succeeds the second is to dispose of the old current directory
pointer.
</para>
 
<para>
The <function>opendir()</function> function is used to open a
directory for reading. This results in an open file object that can be
read to return a sequence of <structname>struct dirent</structname>
objects. The only operations that are allowed on this file are
<function>read</function>, <function>lseek</function> and
<function>close</function>. Each read operation on this file should
return a single <structname>struct dirent</structname> object. When
the end of the directory is reached, zero should be returned. The only
seek operation allowed is a rewind to the start of the directory, by
supplying an offset of zero and a <parameter>whence</parameter>
specifier of <literal>SEEK_SET</literal>.
</para>
 
<para>
Most of these considerations are invisible to clients of a filesystem
since they will access directories via the POSIX
<function>opendir()</function>, <function>readdir()</function> and
<function>closedir()</function> functions.
</para>
 
<para>
Support for the <function>getcwd()</function> function is provided by
three mechanisms. The first is to use the
<literal>FS_INFO_GETCWD</literal> getinfo key on the filesystem to use
any internal support that it has for this. If that fails it falls back
on one of the two other mechanisms. If
<literal>CYGPKG_IO_FILEIO_TRACK_CWD</literal> is set then the current
directory is tracked textually in <function>chdir()</function> and the result of that is
reported in getcwd(). Otherwise an attempt is made to traverse the
directory tree to its root using &quot;..&quot; entries.
</para>
 
<para>
This last option is complicated and expensive, and relies on the
filesystem supporting &quot;.&quot; and &quot;..&quot; entries. This is not always the
case, particularly if the filesystem has been ported from a
non-UNIX-compatible source. Tracking the pathname textually will
usually work, but might not produce optimum results when symbolic
links are being used.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ Synchronization -->
 
<chapter id="fileio-synchronization">
<title>Synchronization</title>
 
<para>
The FILEIO infrastructure provides a synchronization mechanism for
controlling concurrent access to filesystems. This allows existing
filesystems to be ported to eCos, even if they do not have their own
synchronization mechanisms. It also allows new filesystems to be
implemented easily without having to consider the synchronization
issues.
</para>
 
<para>
The infrastructure maintains a mutex for each entry in each of
the main tables: filesystem table, mount table and file table. For
each class of operation each of these mutexes may be locked before the
corresponding filesystem operation is invoked.
</para>
 
<para>
The synchronization protocol required by a filesystem is described
by the <structfield>syncmode</structfield> field of the filesystem
table entry. This is a combination of the following flags:
</para>
 
<variablelist>
<varlistentry>
<term><literal>CYG_SYNCMODE_FILE_FILESYSTEM</literal></term>
<listitem>
<para>
Lock the filesystem table entry mutex
during all filesystem level operations.
</para>
</listitem>
</varlistentry>
 
<varlistentry>
<term><literal>CYG_SYNCMODE_FILE_MOUNTPOINT</literal></term>
<listitem>
<para>
Lock the mount table entry mutex
during all filesystem level operations.
</para>
</listitem>
</varlistentry>
 
<varlistentry>
<term><literal>CYG_SYNCMODE_IO_FILE</literal></term>
<listitem>
<para>
Lock the file table entry mutex during all
I/O operations.
</para>
</listitem>
</varlistentry>
 
<varlistentry>
<term><literal>CYG_SYNCMODE_IO_FILESYSTEM</literal></term>
<listitem>
<para>
Lock the filesystem table entry mutex during all I/O operations.
</para>
</listitem>
</varlistentry>
 
<varlistentry>
<term><literal>CYG_SYNCMODE_IO_MOUNTPOINT</literal></term>
<listitem><para>
Lock the mount table entry mutex during all I/O operations.
</para>
</listitem>
</varlistentry>
 
<varlistentry>
<term><literal>CYG_SYNCMODE_SOCK_FILE</literal></term>
<listitem>
<para>
Lock the file table entry mutex during all socket operations.
</para>
</listitem>
</varlistentry>
 
<varlistentry>
<term><literal>CYG_SYNCMODE_SOCK_NETSTACK</literal></term>
<listitem>
<para>
Lock the network stack table entry mutex during all socket operations.
</para>
</listitem>
</varlistentry>
 
<varlistentry>
<term><literal>CYG_SYNCMODE_NONE</literal></term>
<listitem>
<para>
Perform no locking at all during any operations.
</para>
</listitem>
</varlistentry>
 
</variablelist>
 
<para>
The value of the <structfield>syncmode</structfield> field in the
filesystem table entry will be copied by the infrastructure to the
open file object after a successful <function>open()</function> operation.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ Initialization and Mounting -->
 
<chapter id="fileio-mounting">
<title>Initialization and Mounting</title>
 
<para>
As mentioned previously, mount table entries can be sourced from two
places. Static entries may be defined by using the
<literal>MTAB_ENTRY()</literal> macro. Such entries will be
automatically mounted on system startup. For each entry in the mount
table that has a non-null <structfield>name</structfield> field the
filesystem table is searched for a match with the
<structfield>fsname</structfield> field. If a match is found the
filesystem's <structfield>mount</structfield> entry is called and if
successful the mount table entry marked valid and the
<structfield>fs</structfield> field initialized. The
<function>mount()</function> function is responsible for initializing
the <structfield>root</structfield> field.
</para>
 
 
<para>
The size of the mount table is defined by the configuration value
<literal>CYGNUM_FILEIO_MTAB_MAX</literal>. Any entries that have not
been statically defined are available for use by dynamic mounts.
</para>
 
<para>
A filesystem may be mounted dynamically by calling <function>mount()</function>. This
function has the following prototype:
</para>
 
<programlisting width=72>
int mount( const char *devname,
const char *dir,
const char *fsname);
</programlisting>
 
<para>
The <parameter>devname</parameter> argument identifies a device that
will be used by this filesystem and will be assigned to the
<structfield>devname</structfield> field of the mount table entry.
</para>
 
<para>
The <parameter>dir</parameter> argument is the mount point name, it
will be assigned to the <structfield>name</structfield> field of the
mount table entry.
</para>
 
<para>
The <parameter>fsname</parameter> argument is the name of the
implementing filesystem, it will be assigned to the
<structfield>fsname</structfield> entry of the mount table entry.
</para>
 
<para>
The process of mounting a filesystem dynamically is as follows. First
a search is made of the mount table for an entry with a NULL
<structfield>name</structfield> field to be used for the new mount
point. The filesystem table is then searched for an entry whose name
matches <structfield>fsname</structfield>. If this is successful then
the mount table entry is initialized and the filesystem's
<function>mount()</function> operation called. If this is successful,
the mount table entry is marked valid and the
<structfield>fs</structfield> field initialized.
</para>
 
<para>
Unmounting a filesystem is done by the <function>umount()</function>
function. This can unmount filesystems whether they were mounted
statically or dynamically.
</para>
 
<para>
The <function>umount()</function> function has the following prototype:
</para>
 
<programlisting width=72>
int umount( const char *name );
</programlisting>
 
<para>
The mount table is searched for a match between the
<parameter>name</parameter> argument and the entry
<structfield>name</structfield> field. When a match is found the
filesystem's <function>umount()</function> operation is called and if
successful, the mount table entry is invalidated by setting its
<structfield>valid</structfield> field false and the
<structfield>name</structfield> field to NULL.
</para>
 
<!--
 
 
-->
 
</chapter>
 
<!-- }}} -->
<!-- {{{ Sockets -->
 
<chapter id="fileio-sockets">
<title>Sockets</title>
 
<para>
If a network stack is present, then the FILEIO infrastructure also
provides access to the standard BSD socket calls.
</para>
 
<para>
The netstack table contains entries which describe the network
protocol stacks that are in the system image. Each resident stack
should export an entry to this table using the
<literal>NSTAB_ENTRY()</literal> macro.
</para>
 
<para>
Each table entry has the following structure:
</para>
 
<programlisting width=72>
struct cyg_nstab_entry
{
cyg_bool valid; // true if stack initialized
cyg_uint32 syncmode; // synchronization protocol
char *name; // stack name
char *devname; // hardware device name
CYG_ADDRWORD data; // private data value
 
int (*init)( cyg_nstab_entry *nste );
int (*socket)( cyg_nstab_entry *nste, int domain, int type,
int protocol, cyg_file *file );
};
</programlisting>
 
<para>
This table is analogous to a combination of the filesystem and mount
tables.
</para>
 
<para>
The <structfield>valid</structfield> field is set
<literal>true</literal> if the stack's <function>init()</function>
function returned successfully and the
<structfield>syncmode</structfield> field contains the
<literal>CYG_SYNCMODE_SOCK_*</literal> bits described above.
</para>
 
<!--
 
 
-->
 
<para>
The <structfield>name</structfield> field contains the name of the
protocol stack.
</para>
 
<!--
 
 
-->
 
<para>
The <structfield>devname</structfield> field names the device that the stack is using. This may
reference a device under &quot;/dev&quot;, or may be a name that is only
meaningful to the stack itself.
</para>
 
<!--
 
 
-->
 
<para>
The <function>init()</function> function pointer is called during
system initialization to start the protocol stack running. If it
returns non-zero the <structfield>valid</structfield> field is set
false and the stack will be ignored subsequently.
</para>
 
<para>
The <function>socket()</function> function is called to attempt to create a socket in the
stack. When the <function>socket()</function> API function is called the netstack table is
scanned and for each valid entry the <function>socket()</function>
function pointer is called. If
this returns non-zero then the scan continues to the next valid stack,
or terminates with an error if the end of the table is reached.
</para>
 
<para>
The result of a successful socket call is an initialized file object
with the <structfield>f_xops</structfield> field pointing to the
following structure:
</para>
 
<programlisting width=72>
struct cyg_sock_ops
{
int (*bind) ( cyg_file *fp, const sockaddr *sa, socklen_t len );
int (*connect) ( cyg_file *fp, const sockaddr *sa, socklen_t len );
int (*accept) ( cyg_file *fp, cyg_file *new_fp,
struct sockaddr *name, socklen_t *anamelen );
int (*listen) ( cyg_file *fp, int len );
int (*getname) ( cyg_file *fp, sockaddr *sa, socklen_t *len, int peer );
int (*shutdown) ( cyg_file *fp, int flags );
int (*getsockopt)( cyg_file *fp, int level, int optname,
void *optval, socklen_t *optlen);
int (*setsockopt)( cyg_file *fp, int level, int optname,
const void *optval, socklen_t optlen);
int (*sendmsg) ( cyg_file *fp, const struct msghdr *m,
int flags, ssize_t *retsize );
int (*recvmsg) ( cyg_file *fp, struct msghdr *m,
socklen_t *namelen, ssize_t *retsize );
};
</programlisting>
 
<para>
It should be obvious from the names of these functions which API calls
they provide support for. The <function>getname()</function> function
pointer provides support for both <function>getsockname()</function>
and <function>getpeername()</function> while the
<function>sendmsg()</function> and <function>recvmsg()</function>
function pointers provide support for <function>send()</function>,
<function>sendto()</function>, <function>sendmsg()</function>,
<function>recv()</function>, <function>recvfrom()</function> and
<function>recvmsg()</function> as appropriate.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ Select -->
 
<chapter id="fileio-select">
<title>Select</title>
 
<para>
The infrastructure provides support for implementing a select
mechanism. This is modeled on the mechanism in the BSD kernel, but has
been modified to make it implementation independent.
</para>
 
<para>
The main part of the mechanism is the <function>select()</function>
API call. This processes its arguments and calls the
<function>fo_select()</function> function pointer on all file objects
referenced by the file descriptor sets passed to it. If the same
descriptor appears in more than one descriptor set, the
<function>fo_select()</function> function will be called separately
for each appearance.
</para>
 
<para>
The <parameter>which</parameter> argument of the
<function>fo_select()</function> function will either be
<literal>CYG_FREAD</literal> to test for read conditions,
<literal>CYG_FWRITE</literal> to test for write conditions or zero to
test for exceptions. For each of these options the function should
test whether the condition is satisfied and if so return true. If it
is not satisfied then it should call
<function>cyg_selrecord()</function> with the
<parameter>info</parameter> argument that was passed to the function
and a pointer to a <structname>cyg_selinfo</structname> structure.
</para>
 
<para>
The <structname>cyg_selinfo</structname> structure is used to record information about current
select operations. Any object that needs to support select must
contain an instance of this structure. Separate <structname>cyg_selinfo</structname>
structures should be kept for each of the options that the object can
select on - read, write or exception.
</para>
 
<para>
If none of the file objects report that the select condition is
satisfied, then the <function>select()</function> API function puts
the calling thread to sleep waiting either for a condition to become
satisfied, or for the optional timeout to expire.
</para>
 
<para>
A selectable object must have some asynchronous activity that may
cause a select condition to become true - either via interrupts or the
activities of other threads. Whenever a selectable condition is
satisfied, the object should call <function>cyg_selwakeup()</function> with a pointer to
the appropriate <structname>cyg_selinfo</structname> structure. If the thread is still waiting,
this will cause it to wake up and repeat its poll of the file
descriptors. This time around, the object that caused the wakeup
should indicate that the select condition is satisfied, and the
<function>select()</function> API call will return.
</para>
 
<para>
Note that <function>select()</function> does not exhibit real time
behaviour: the iterative poll of the descriptors, and the wakeup
mechanism mitigate against this. If real time response to device or
socket I/O is required then separate threads should be devoted to each
device of interest and should use blocking calls to wait for a
condition to become ready.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ Devices -->
 
<chapter id="fileio-devices">
<title>Devices</title>
 
<para>
Devices are accessed by means of a pseudo-filesystem, &quot;devfs&quot;, that is
mounted on &quot;/dev&quot;. Open operations are translated into calls to
<function>cyg_io_lookup()</function> and if successful result in a file object whose
<structfield>f_ops</structfield> functions translate filesystem API functions into calls into
the device API.
</para>
 
</chapter>
 
<!-- }}} -->
<!-- {{{ Writing a New Filesystem -->
 
<chapter id="fileio-writing">
<title>Writing a New Filesystem</title>
 
<para>
To create a new filesystem it is necessary to define the fstab entry
and the file IO operations. The easiest way to do this is to copy an
existing filesystem: either the test filesystem in the FILEIO package,
or the RAM or ROM filesystem packages.
</para>
 
<para>
To make this clearer, the following is a brief tour of the FILEIO
relevant parts of the RAM filesystem.
</para>
 
<para>
First, it is necessary to provide forward definitions of the functions
that constitute the filesystem interface:
</para>
 
<programlisting width=72>
//==========================================================================
// Forward definitions
 
// Filesystem operations
static int ramfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
static int ramfs_umount ( cyg_mtab_entry *mte );
static int ramfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *fte );
static int ramfs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int ramfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int ramfs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int ramfs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 );
static int ramfs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type );
static int ramfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *fte );
static int ramfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out );
static int ramfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf);
static int ramfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
static int ramfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
 
// File operations
static int ramfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int ramfs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int ramfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
static int ramfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
static int ramfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode );
static int ramfs_fo_close (struct CYG_FILE_TAG *fp);
static int ramfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf );
static int ramfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
static int ramfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
 
// Directory operations
static int ramfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int ramfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
</programlisting>
 
<para>
We define all of the fstab entries and all of the file IO
operations. We also define alternatives for the
<structfield>fo_read</structfield> and
<structfield>fo_lseek</structfield> file IO operations.
</para>
 
<para>
We can now define the filesystem table entry. There is a macro,
<literal>FSTAB_ENTRY</literal> to do this:
</para>
 
 
<programlisting width=72>
//==========================================================================
// Filesystem table entries
 
// -------------------------------------------------------------------------
// Fstab entry.
// This defines the entry in the filesystem table.
// For simplicity we use _FILESYSTEM synchronization for all accesses since
// we should never block in any filesystem operations.
 
FSTAB_ENTRY( ramfs_fste, "ramfs", 0,
CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
ramfs_mount,
ramfs_umount,
ramfs_open,
ramfs_unlink,
ramfs_mkdir,
ramfs_rmdir,
ramfs_rename,
ramfs_link,
ramfs_opendir,
ramfs_chdir,
ramfs_stat,
ramfs_getinfo,
ramfs_setinfo);
</programlisting>
 
<para>
The first argument to this macro gives the fstab entry a name, the
remainder are initializers for the field of the structure.
</para>
 
<para>
We must also define the file operations table that is installed in all
open file table entries:
</para>
 
<programlisting width=72>
// -------------------------------------------------------------------------
// File operations.
// This set of file operations are used for normal open files.
 
static cyg_fileops ramfs_fileops =
{
ramfs_fo_read,
ramfs_fo_write,
ramfs_fo_lseek,
ramfs_fo_ioctl,
cyg_fileio_seltrue,
ramfs_fo_fsync,
ramfs_fo_close,
ramfs_fo_fstat,
ramfs_fo_getinfo,
ramfs_fo_setinfo
};
</programlisting>
 
<para>
These all point to functions supplied by the filesystem except the
<structfield>fo_select</structfield> field which is filled with a
pointer to <function>cyg_fileio_seltrue()</function>. This is provided
by the FILEIO package and is a select function that always returns
true to all operations.
</para>
 
<para>
Finally, we need to define a set of file operations for use when
reading directories. This table only defines the
<structfield>fo_read</structfield> and
<structfield>fo_lseek</structfield> operations. The rest are filled
with stub functions supplied by the FILEIO package that just return an
error code.
</para>
 
<programlisting width=72>
// -------------------------------------------------------------------------
// Directory file operations.
// This set of operations are used for open directories. Most entries
// point to error-returning stub functions. Only the read, lseek and
// close entries are functional.
 
static cyg_fileops ramfs_dirops =
{
ramfs_fo_dirread,
(cyg_fileop_write *)cyg_fileio_enosys,
ramfs_fo_dirlseek,
(cyg_fileop_ioctl *)cyg_fileio_enosys,
cyg_fileio_seltrue,
(cyg_fileop_fsync *)cyg_fileio_enosys,
ramfs_fo_close,
(cyg_fileop_fstat *)cyg_fileio_enosys,
(cyg_fileop_getinfo *)cyg_fileio_enosys,
(cyg_fileop_setinfo *)cyg_fileio_enosys
};
</programlisting>
 
<para>
If the filesystem wants to have an instance automatically mounted on
system startup, it must also define a mount table entry. This is done
with the <literal>MTAB_ENTRY</literal> macro. This is an example from
the test filesystem of how this is used:
</para>
 
<programlisting width=72>
MTAB_ENTRY( testfs_mte1,
"/",
"testfs",
"",
0);
</programlisting>
 
<para>
The first argument provides a name for the table entry. The following
arguments provide initialization for the
<structfield>name</structfield>, <structfield>fsname</structfield>,
<structfield>devname</structfield> and <structfield>data</structfield>
fields respectively.
</para>
 
<para>
These definitions are adequate to let the new filesystem interact
with the FILEIO package. The new filesystem now needs to be fleshed
out with implementations of the functions defined above. Obviously,
the exact form this takes will depend on what the filesystem is
intended to do. Take a look at the RAM and ROM filesystems for
examples of how this has been done.
</para>
 
</chapter>
 
<!-- }}} -->
 
</part>
/v2_0/src/dir.cxx
0,0 → 1,225
//==========================================================================
//
// dir.cxx
//
// Fileio directory support
//
//==========================================================================
//####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 directory support
// Description: Support for directory operations.
//
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <stdarg.h> // for fcntl()
 
#include "fio.h" // Private header
 
#include <dirent.h> // struct dirent
 
//==========================================================================
 
#define DIROPEN_RETURN_ERR( err ) \
CYG_MACRO_START \
errno = err; \
CYG_REPORT_RETVAL( NULL ); \
return NULL; \
CYG_MACRO_END
 
//==========================================================================
// 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)
 
//==========================================================================
// Open a directory for reading
 
extern DIR *opendir( const char *dirname )
{
FILEIO_ENTRY();
 
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 = dirname;
 
fd = cyg_fd_alloc(1); // Never return fd 0
 
if( fd < 0 )
DIROPEN_RETURN_ERR(EMFILE);
file = cyg_file_alloc();
 
if( file == NULL )
{
cyg_fd_free(fd);
DIROPEN_RETURN_ERR(ENFILE);
}
ret = cyg_mtab_lookup( &dir, &name, &mte );
if( 0 != ret )
{
cyg_fd_free(fd);
cyg_file_free(file);
DIROPEN_RETURN_ERR(ENOENT);
}
 
LOCK_FS( mte );
ret = mte->fs->opendir( mte, dir, name, file );
UNLOCK_FS( mte );
if( 0 != ret )
{
cyg_fd_free(fd);
cyg_file_free(file);
DIROPEN_RETURN_ERR(ret);
}
 
file->f_flag |= CYG_FDIR|CYG_FREAD;
file->f_mte = mte;
file->f_syncmode = mte->fs->syncmode;
cyg_fd_assign( fd, file );
 
DIR *dirp = (DIR *)fd;
FILEIO_RETURN_VALUE(dirp);
}
 
//==========================================================================
// Read a directory entry.
// This is the thread-unsafe version that uses a static result buffer.
// It just calls the thread-safe version to do the work.
 
extern struct dirent *readdir( DIR *dirp )
{
FILEIO_ENTRY();
static struct dirent ent;
struct dirent *result;
int err;
 
err = readdir_r( dirp, &ent, &result );
 
if( err != 0 )
{
errno = err;
FILEIO_RETURN_VALUE( NULL );
}
FILEIO_RETURN_VALUE( result );
}
 
//==========================================================================
 
extern int readdir_r( DIR *dirp, struct dirent *entry, struct dirent **result )
{
FILEIO_ENTRY();
 
int fd = (int)dirp;
ssize_t res;
 
*result = NULL;
res = read( fd, (void *)entry, sizeof(struct dirent));
 
if( res < 0 )
{
FILEIO_RETURN_VALUE( errno );
}
if( res > 0 )
*result = entry;
FILEIO_RETURN( ENOERR );
}
 
//==========================================================================
 
extern void rewinddir( DIR *dirp )
{
FILEIO_ENTRY();
 
int fd = (int)dirp;
 
lseek( fd, 0, SEEK_SET );
FILEIO_RETURN_VOID();
}
 
//==========================================================================
 
extern int closedir( DIR *dirp )
{
FILEIO_ENTRY();
 
int fd = (int)dirp;
int err = close( fd );
 
FILEIO_RETURN_VALUE( err );
}
 
// -------------------------------------------------------------------------
// EOF dir.cxx
/v2_0/src/select.cxx
0,0 → 1,392
//==========================================================================
//
// select.cxx
//
// Fileio select() support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Nick Garnett
//
// 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 select() support
// Description: Support for select().
//
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <stdarg.h> // for fcntl()
 
#include "fio.h" // Private header
 
#include <sys/select.h> // select header
 
#include <cyg/kernel/sched.hxx> // scheduler definitions
#include <cyg/kernel/thread.hxx> // thread definitions
#include <cyg/kernel/mutex.hxx> // mutex definitions
#include <cyg/kernel/clock.hxx> // clock definitions
 
#include <cyg/kernel/sched.inl>
#include <cyg/kernel/thread.inl>
#include <cyg/kernel/clock.inl>
 
//==========================================================================
// File object locking
 
#define LOCK_FILE( fp ) cyg_file_lock( fp )
 
#define UNLOCK_FILE( fp ) cyg_file_unlock( fp )
 
//==========================================================================
// Local variables
 
// Mutex for serializing select processing. This essntially controls
// access to the contents of the selinfo structures embedded in the
// client system data structures.
static Cyg_Mutex select_mutex CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
 
// Condition variable where any thread that is waiting for a select to
// fire is suspended. Note that select is not intended to be a real time
// operation. Whenever any selectable event occurs, all selecting threads
// will be resumed. They must then rescan their selectees and resuspend if
// necessary.
static Cyg_Condition_Variable selwait( select_mutex ) CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
 
static volatile cyg_uint32 selwake_count = 0;
 
//==========================================================================
// Timeval to ticks conversion support
 
// Converters from sec and us to ticks
static struct Cyg_Clock::converter us_converter, sec_converter;
 
static cyg_bool converters_initialized = false;
 
externC cyg_tick_count cyg_timeval_to_ticks( const struct timeval *tv )
{
if( !converters_initialized )
{
// Create the converters we need.
Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000, &us_converter );
Cyg_Clock::real_time_clock->get_other_to_clock_converter( 1000000000, &sec_converter );
 
converters_initialized = true;
}
// Short circuit zero timeval
if( tv->tv_sec == 0 && tv->tv_usec == 0 )
{
return 0;
}
// Convert the seconds field to ticks.
cyg_tick_count ticks = Cyg_Clock::convert( tv->tv_sec, &sec_converter );
 
// Convert the nanoseconds. This will round down to nearest whole tick.
ticks += Cyg_Clock::convert( (cyg_tick_count)tv->tv_usec, &us_converter );
 
return ticks;
}
 
//==========================================================================
// Select API function
 
static int
cyg_pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
struct timeval *tv, const sigset_t *mask)
{
FILEIO_ENTRY();
 
int error = ENOERR;
int fd, mode, num;
cyg_file *fp;
fd_set in_res, out_res, ex_res; // Result sets
fd_set *selection[3], *result[3];
cyg_tick_count ticks;
int mode_type[] = {CYG_FREAD, CYG_FWRITE, 0};
cyg_uint32 wake_count;
sigset_t oldmask;
 
FD_ZERO(&in_res);
FD_ZERO(&out_res);
FD_ZERO(&ex_res);
 
// Set up sets
selection[0] = in; result[0] = &in_res;
selection[1] = out; result[1] = &out_res;
selection[2] = ex; result[2] = &ex_res;
 
// Compute end time
if (tv)
ticks = cyg_timeval_to_ticks( tv );
else ticks = 0;
 
// Lock the mutex
select_mutex.lock();
 
// Scan sets for possible I/O until something found, timeout or error.
while (!error)
{
wake_count = selwake_count;
num = 0; // Total file descriptors "ready"
for (mode = 0; !error && mode < 3; mode++)
{
if (selection[mode]) {
for (fd = 0; !error && fd < nfd; fd++)
{
if (FD_ISSET(fd, selection[mode]))
{
fp = cyg_fp_get( fd );
if( fp == NULL )
{
error = EBADF;
break;
}
 
if ((*fp->f_ops->fo_select)(fp, mode_type[mode], 0))
{
FD_SET(fd, result[mode]);
num++;
}
 
cyg_fp_free( fp );
}
}
}
}
if (num)
{
// Found something, update user's sets
if (in) FD_COPY( &in_res, in );
if (out) FD_COPY( &out_res, out );
if (ex) FD_COPY( &ex_res, ex );
select_mutex.unlock();
CYG_FILEIO_DELIVER_SIGNALS( mask );
FILEIO_RETURN_VALUE(num);
}
 
Cyg_Scheduler::lock();
 
// Switch to the supplied signal mask. This will permit delivery
// of any signals that might terminate this select operation.
CYG_FILEIO_SIGMASK_SET( mask, &oldmask );
do
{
 
// We need to see if any signals have been posted while we
// were testing all those files. The handlers will not
// have run because we have ASRs inhibited but the signal
// will have been set pending.
 
if( CYG_FILEIO_SIGPENDING() )
{
// There are pending signals so we need to terminate
// the select operation and return EINTR. Handlers for
// the pending signals will be called just before we
// return.
 
error = EINTR;
break;
}
if( wake_count == selwake_count )
{
// Nothing found, see if we want to wait
if (tv)
{
// Special case of "poll"
if (ticks == 0)
{
error = EAGAIN;
break;
}
 
ticks += Cyg_Clock::real_time_clock->current_value();
if( !selwait.wait( ticks ) )
{
// A non-standard wakeup, if the current time is equal to
// or past the timeout, return zero. Otherwise return
// EINTR, since we have been released.
 
if( Cyg_Clock::real_time_clock->current_value() >= ticks )
{
error = EAGAIN;
break;
}
else error = EINTR;
}
 
ticks -= Cyg_Clock::real_time_clock->current_value();
}
else
{
// Wait forever (until something happens)
if( !selwait.wait() )
error = EINTR;
}
}
 
} while(0);
 
CYG_FILEIO_SIGMASK_SET( &oldmask, NULL );
Cyg_Scheduler::unlock();
} // while(!error)
 
select_mutex.unlock();
// If the error code is EAGAIN, this means that a timeout has
// happened. We return zero in that case, rather than a proper
// error code.
// If the error code is EINTR, then a signal may be pending
// delivery. Call back into the POSIX package to handle it.
if( error == EAGAIN )
FILEIO_RETURN_VALUE(0);
else if( error == EINTR )
CYG_FILEIO_DELIVER_SIGNALS( mask );
 
FILEIO_RETURN(error);
}
 
// -------------------------------------------------------------------------
// Select API function
 
__externC int
select(int nfd, fd_set *in, fd_set *out, fd_set *ex, struct timeval *tv)
{
return cyg_pselect(nfd, in, out, ex, tv, NULL);
}
 
// -------------------------------------------------------------------------
// Pselect API function
//
// This is derived from the POSIX-200X specification.
 
#ifdef CYGPKG_POSIX
 
__externC int
pselect(int nfd, fd_set *in, fd_set *out, fd_set *ex,
const struct timespec *ts, const sigset_t *sigmask)
{
struct timeval tv;
 
if (ts != NULL)
{
tv.tv_sec = ts->tv_sec;
tv.tv_usec = ts->tv_nsec/1000;
}
 
return cyg_pselect(nfd, in, out, ex, &tv, sigmask);
}
 
#endif
 
//==========================================================================
// Select support functions.
 
// -------------------------------------------------------------------------
// cyg_selinit() is used to initialize a selinfo structure
 
void cyg_selinit( struct CYG_SELINFO_TAG *sip )
{
sip->si_info = 0;
sip->si_thread = 0;
}
 
// -------------------------------------------------------------------------
// cyg_selrecord() is called when a client device needs to register
// the current thread for selection.
 
void cyg_selrecord( CYG_ADDRWORD info, struct CYG_SELINFO_TAG *sip )
{
sip->si_info = info;
sip->si_thread = (CYG_ADDRESS)Cyg_Thread::self();
}
 
// -------------------------------------------------------------------------
// cyg_selwakeup() is called when the client device matches the select
// criterion, and needs to wake up a selector.
 
void cyg_selwakeup( struct CYG_SELINFO_TAG *sip )
{
// We don't actually use the si_info field of selinfo at present.
// A potential use would be to select one of several selwait condition
// variables to signal. However, that would only be necessary if we
// end up having lots of threads in select.
 
Cyg_Scheduler::lock();
if( sip->si_thread != 0 )
{
// If the thread pointer is still present, this selection has
// not been fired before. We just wake up all threads waiting,
// regardless of whether they are waiting for this event or
// not. This avoids any race conditions, and is consistent
// with the behaviour of the BSD kernel.
sip->si_thread = 0;
selwait.broadcast();
selwake_count++;
 
}
 
Cyg_Scheduler::unlock();
}
 
// -------------------------------------------------------------------------
// EOF select.cxx
/v2_0/src/file.cxx
0,0 → 1,760
//==========================================================================
//
// 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
/v2_0/src/fio.h
0,0 → 1,226
#ifndef CYGONCE_FIO_H
#define CYGONCE_FIO_H
//=============================================================================
//
// fio.h
//
// Fileio private header
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Nick Garnett
//
// 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 private header
// Description: This file contains private definitions for communication
// between the parts of the fileio package.
//
// Usage:
// #include "fio.h"
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/io_fileio.h>
#include <pkgconf/isoinfra.h>
 
#include <cyg/infra/cyg_type.h>
 
#include <stddef.h> // NULL, size_t
#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
 
#include <cyg/fileio/fileio.h>
#include <cyg/fileio/sockio.h>
 
#include <errno.h>
 
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#include <cyg/kernel/mutex.hxx> // mutex definitions
 
#define FILEIO_MUTEX_LOCK(_m_) ((_m_).lock())
#define FILEIO_MUTEX_UNLOCK(_m_) ((_m_).unlock())
 
#else
#define FILEIO_MUTEX_LOCK(_m_)
#define FILEIO_MUTEX_UNLOCK(_m_)
#endif
 
 
//=============================================================================
// POSIX API support
 
#ifdef CYGPKG_POSIX
 
#include <cyg/posix/export.h>
 
#define CYG_FILEIO_FUNCTION_START() CYG_POSIX_FUNCTION_START()
 
#define CYG_FILEIO_FUNCTION_FINISH() CYG_POSIX_FUNCTION_FINISH()
 
#define CYG_FILEIO_SIGMASK_SET( __set, __oset ) \
CYG_PTHREAD_SIGMASK_SET( __set, __oset )
 
#define CYG_FILEIO_SIGPENDING() CYG_POSIX_SIGPENDING()
 
#define CYG_FILEIO_DELIVER_SIGNALS( __mask ) \
CYG_POSIX_DELIVER_SIGNALS( __mask )
 
#else
 
#define CYG_FILEIO_FUNCTION_START() CYG_EMPTY_STATEMENT
 
#define CYG_FILEIO_FUNCTION_FINISH() CYG_EMPTY_STATEMENT
 
#define CYG_FILEIO_SIGMASK_SET( __set, __oset ) CYG_EMPTY_STATEMENT
 
#define CYG_FILEIO_SIGPENDING() (0)
 
#define CYG_FILEIO_DELIVER_SIGNALS( __mask ) CYG_EMPTY_STATEMENT
 
typedef int sigset_t;
 
#endif
 
//=============================================================================
// Fileio function entry and return macros.
 
// Handle entry to a fileio package function.
#define FILEIO_ENTRY() \
CYG_REPORT_FUNCTYPE( "returning %d" ); \
CYG_FILEIO_FUNCTION_START(); \
 
// Do a fileio package defined return. This requires the error code
// to be placed in errno, and if it is non-zero, -1 returned as the
// result of the function. This also gives us a place to put any
// generic tidyup handling needed for things like signal delivery and
// cancellation.
#define FILEIO_RETURN(err) \
CYG_MACRO_START \
int __retval = 0; \
CYG_FILEIO_FUNCTION_FINISH(); \
if( err != 0 ) __retval = -1, errno = err; \
CYG_REPORT_RETVAL( __retval ); \
return __retval; \
CYG_MACRO_END
 
#define FILEIO_RETURN_VALUE(val) \
CYG_MACRO_START \
CYG_FILEIO_FUNCTION_FINISH(); \
CYG_REPORT_RETVAL( val ); \
return val; \
CYG_MACRO_END
 
#define FILEIO_RETURN_VOID() \
CYG_MACRO_START \
CYG_FILEIO_FUNCTION_FINISH(); \
CYG_REPORT_RETURN(); \
return; \
CYG_MACRO_END
 
//=============================================================================
// Cancellation support
// If the POSIX package is present we want to include cancellation points
// in the routines that are defined to contain them.
// The macro CYG_CANCELLATION_POINT does this.
 
#ifdef CYGINT_ISO_PTHREAD_IMPL
 
# include <pthread.h>
 
# define CYG_CANCELLATION_POINT pthread_testcancel()
 
#else
 
# define CYG_CANCELLATION_POINT CYG_EMPTY_STATEMENT
 
#endif
 
//=============================================================================
// Internal exports
 
//-----------------------------------------------------------------------------
// Exports from misc.cxx
 
// Current directory info
__externC cyg_mtab_entry *cdir_mtab_entry;
__externC cyg_dir cdir_dir;
 
__externC int cyg_mtab_lookup( cyg_dir *dir, const char **name, cyg_mtab_entry **mte);
 
__externC void cyg_fs_lock( cyg_mtab_entry *mte, cyg_uint32 syncmode );
 
__externC void cyg_fs_unlock( cyg_mtab_entry *mte, cyg_uint32 syncmode );
 
//-----------------------------------------------------------------------------
// Exports from fd.cxx
 
__externC void cyg_fd_init();
 
__externC cyg_file *cyg_file_alloc();
 
__externC void cyg_file_free(cyg_file * fp);
 
__externC int cyg_fd_alloc(int low);
 
__externC void cyg_fd_assign(int fd, cyg_file *fp);
 
__externC int cyg_fd_free(int fd);
 
__externC cyg_file *cyg_fp_get( int fd );
 
__externC void cyg_fp_free( cyg_file *fp );
 
__externC void cyg_file_lock( cyg_file *fp, cyg_uint32 syncmode );
 
__externC void cyg_file_unlock( cyg_file *fp, cyg_uint32 syncmode );
 
//-----------------------------------------------------------------------------
// Exports from socket.cxx
 
__externC void cyg_nstab_init();
 
//-----------------------------------------------------------------------------
#endif // ifndef CYGONCE_FIO_H
// End of fio.h
/v2_0/src/devfs.cxx
0,0 → 1,501
//==========================================================================
//
// devfs.cxx
//
// Fileio device filesystem
//
//==========================================================================
//####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 device filesystem
// Description: This file implements a simple filesystem that interfaces
// to the existing device IO subsystem.
//
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include "fio.h" // Private header
 
#include <cyg/io/devtab.h> // device subsystem
#include <cyg/io/config_keys.h> // CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN
 
//==========================================================================
// Forward definitions
 
// Filesystem operations
static int dev_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
static int dev_umount ( cyg_mtab_entry *mte );
static int dev_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *fte );
static int dev_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int dev_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int dev_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int dev_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 );
static int dev_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type );
static int dev_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *fte );
static int dev_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out );
static int dev_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf);
static int dev_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
static int dev_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
 
// File operations
static int dev_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int dev_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int dev_fo_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
static int dev_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
static int dev_fo_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
static int dev_fo_fsync (struct CYG_FILE_TAG *fp, int mode );
static int dev_fo_close (struct CYG_FILE_TAG *fp);
static int dev_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf );
static int dev_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
static int dev_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
 
 
//==========================================================================
// Filesystem table entries
 
FSTAB_ENTRY( dev_fste, "devfs", 0,
CYG_SYNCMODE_NONE, // dev system has its own sync mechanism
dev_mount,
dev_umount,
dev_open,
dev_unlink,
dev_mkdir,
dev_rmdir,
dev_rename,
dev_link,
dev_opendir,
dev_chdir,
dev_stat,
dev_getinfo,
dev_setinfo);
 
MTAB_ENTRY( dev_mte,
"/dev",
"devfs",
"",
0);
 
static cyg_fileops dev_fileops =
{
dev_fo_read,
dev_fo_write,
dev_fo_lseek,
dev_fo_ioctl,
dev_fo_select,
dev_fo_fsync,
dev_fo_close,
dev_fo_fstat,
dev_fo_getinfo,
dev_fo_setinfo
};
 
//==========================================================================
// Filesystem operations
 
// -------------------------------------------------------------------------
 
static int dev_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
{
// Nothing to do here. The device IO subsystem has already initialized
// iteslf, and the fileio infrastructure will do the rest.
return 0;
}
 
// -------------------------------------------------------------------------
 
static int dev_umount ( cyg_mtab_entry *mte )
{
// Nothing to do here.
return 0;
}
 
// -------------------------------------------------------------------------
 
static int dev_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *file )
{
Cyg_ErrNo err;
cyg_io_handle_t handle;
 
// The name we are passed will point to the first character after
// "/dev/". We know that the full string contains the prefix string,
// so we back the pointer up by 5 chars.
// A better approach would be for the device table entries to only
// contain the part of the string after the prefix.
 
name -= 5;
err = cyg_io_lookup( name, &handle );
 
if( err < 0 )
return -err;
 
// If we want non-blocking mode, configure the device for it.
if( (mode & (O_NONBLOCK|O_RDONLY)) == (O_NONBLOCK|O_RDONLY) )
{
cyg_uint32 f = 0;
cyg_uint32 fsize = sizeof(f);
err = cyg_io_set_config( handle, CYG_IO_SET_CONFIG_READ_BLOCKING,
(void *)&f, &fsize);
if( err < 0 )
return -err;
}
 
if( (mode & (O_NONBLOCK|O_WRONLY)) == (O_NONBLOCK|O_WRONLY) )
{
cyg_uint32 f = 0;
cyg_uint32 fsize = sizeof(f);
err = cyg_io_set_config( handle, CYG_IO_SET_CONFIG_WRITE_BLOCKING,
(void *)&f, &fsize);
if( err < 0 )
return -err;
}
// Initialize the file object
file->f_flag |= mode & CYG_FILE_MODE_MASK;
file->f_type = CYG_FILE_TYPE_FILE;
file->f_ops = &dev_fileops;
file->f_offset = 0;
file->f_data = (CYG_ADDRWORD)handle;
file->f_xops = 0;
 
return 0;
}
 
// -------------------------------------------------------------------------
 
static int dev_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
{
return EROFS;
}
 
// -------------------------------------------------------------------------
 
static int dev_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
{
return EROFS;
}
 
// -------------------------------------------------------------------------
 
static int dev_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
{
return EROFS;
}
 
// -------------------------------------------------------------------------
 
static int dev_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 )
{
return EROFS;
}
 
// -------------------------------------------------------------------------
 
static int dev_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type )
{
return EROFS;
}
 
// -------------------------------------------------------------------------
 
static int dev_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *fte )
{
return ENOTDIR;
}
 
// -------------------------------------------------------------------------
 
static int dev_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out )
{
return ENOTDIR;
}
 
// -------------------------------------------------------------------------
 
static int dev_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf)
{
Cyg_ErrNo err;
cyg_io_handle_t handle;
 
name -= 5; // See comment in dev_open()
err = cyg_io_lookup( name, &handle );
 
if( err < 0 )
return -err;
 
// Just fill in the stat buffer with some constant values.
 
// FIXME: change this when block devices are available
buf->st_mode = __stat_mode_CHR;
 
buf->st_ino = (ino_t)handle; // map dev handle to inode
buf->st_dev = 0; // (dev_t)handle; // same with dev id
buf->st_nlink = 0;
buf->st_uid = 0;
buf->st_gid = 0;
buf->st_size = 0;
buf->st_atime = 0;
buf->st_mtime = 0;
buf->st_ctime = 0;
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int dev_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len )
{
return ENOSYS;
}
 
// -------------------------------------------------------------------------
 
static int dev_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len )
{
return ENOSYS;
}
 
//==========================================================================
// File operations
 
 
// -------------------------------------------------------------------------
 
static int dev_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
Cyg_ErrNo err = 0;
int i;
 
// Now loop over the iovecs until they are all done, or
// we get an error.
for( i = 0; i < uio->uio_iovcnt; i++ )
{
cyg_iovec *iov = &uio->uio_iov[i];
cyg_uint32 len = iov->iov_len;
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)fp->f_data;
 
if (t->status & CYG_DEVTAB_STATUS_BLOCK)
err = cyg_io_bread( (cyg_io_handle_t)t,
iov->iov_base,
&len, fp->f_offset);
else
err = cyg_io_read( (cyg_io_handle_t)t,
iov->iov_base,
&len);
 
if( -EAGAIN == err ) // must be in non-blocking mode
{
uio->uio_resid -= len;
return ENOERR;
}
if( err < 0 ) break;
 
uio->uio_resid -= len;
}
return -err;
}
 
// -------------------------------------------------------------------------
 
static int dev_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
Cyg_ErrNo err = 0;
int i;
 
// Now loop over the iovecs until they are all done, or
// we get an error.
for( i = 0; i < uio->uio_iovcnt; i++ )
{
cyg_iovec *iov = &uio->uio_iov[i];
cyg_uint32 len = iov->iov_len;
cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)fp->f_data;
 
if (t->status & CYG_DEVTAB_STATUS_BLOCK)
err = cyg_io_bwrite( (cyg_io_handle_t)t,
iov->iov_base,
&len, fp->f_offset);
else
err = cyg_io_write( (cyg_io_handle_t)t,
iov->iov_base,
&len);
 
if( -EAGAIN == err ) // must be in non-blocking mode
{
uio->uio_resid -= len;
return ENOERR;
}
if( err < 0 ) break;
 
uio->uio_resid -= len;
}
 
return -err;
}
 
// -------------------------------------------------------------------------
 
static int dev_fo_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
{
// All current devices have no notion of position. Just return zero
// as the new position.
 
*pos = 0;
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int dev_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data)
{
return ENOSYS;
}
 
// -------------------------------------------------------------------------
 
static cyg_bool dev_fo_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info)
{
return cyg_io_select( (cyg_io_handle_t)fp->f_data,
which,
info);
}
 
// -------------------------------------------------------------------------
 
static int dev_fo_fsync (struct CYG_FILE_TAG *fp, int mode )
{
Cyg_ErrNo err;
 
err = cyg_io_get_config((cyg_io_handle_t)fp->f_data,
CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN,
NULL, NULL);
 
return -err;
}
 
// -------------------------------------------------------------------------
 
static int dev_fo_close (struct CYG_FILE_TAG *fp)
{
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int dev_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf )
{
// Just fill in the stat buffer with some constant values.
 
// FIXME: change this when block devices are available
buf->st_mode = __stat_mode_CHR;
 
buf->st_ino = (ino_t)fp->f_data; // map dev handle to inode
buf->st_dev = (dev_t)fp->f_data; // same with dev id
buf->st_nlink = 0;
buf->st_uid = 0;
buf->st_gid = 0;
buf->st_size = 0;
buf->st_atime = 0;
buf->st_mtime = 0;
buf->st_ctime = 0;
return ENOERR;
}
 
// -------------------------------------------------------------------------
 
static int dev_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
{
Cyg_ErrNo err = 0;
cyg_uint32 ll = len;
err = cyg_io_get_config( (cyg_io_handle_t)fp->f_data, key, buf, &ll );
return -err;
}
 
// -------------------------------------------------------------------------
 
static int dev_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
{
Cyg_ErrNo err = 0;
cyg_uint32 ll = len;
err = cyg_io_set_config( (cyg_io_handle_t)fp->f_data, key, buf, &ll );
return -err;
}
 
// -------------------------------------------------------------------------
// EOF devfs.cxx
/v2_0/src/io.cxx
0,0 → 1,484
//==========================================================================
//
// io.cxx
//
// Fileio IO operations
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Gary Thomas
//
// 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 IO operations
// Description: These are the functions that operate on open files,
// such as read(), write(), fstat() etc.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <stdarg.h> // for fcntl()
 
#include "fio.h" // Private header
 
#include <cyg/kernel/mutex.hxx> // mutex definitions
 
//==========================================================================
// File object locking
 
#define LOCK_FILE( fp ) cyg_file_lock( fp, fp->f_syncmode )
 
#define UNLOCK_FILE( fp ) cyg_file_unlock( fp, fp->f_syncmode )
 
//==========================================================================
// Common wrapper for read/write using an iovec descriptor
// 'direction' should be O_RDONLY for readv, O_WRONLY for writev
 
static ssize_t
readwritev( int fd, const cyg_iovec *_iov, int iov_len, int direction )
{
FILEIO_ENTRY();
 
CYG_CANCELLATION_POINT;
ssize_t cnt, len;
int ret, _idx;
cyg_file *fp;
cyg_iovec iov[CYGNUM_FILEIO_IOVEC_MAX];
if( iov_len > CYGNUM_FILEIO_IOVEC_MAX )
FILEIO_RETURN(EINVAL);
 
// Copy 'iovec' structure since it's supposed to be "const"
// and some lower level routines might want to change it.
// Also accumulate the length of the total I/O request
len = 0;
for (_idx = 0; _idx < iov_len; _idx++) {
len += _iov[_idx].iov_len;
iov[_idx].iov_base = _iov[_idx].iov_base;
iov[_idx].iov_len = _iov[_idx].iov_len;
}
 
if( len > SSIZE_MAX )
FILEIO_RETURN(EINVAL);
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( (fp->f_flag & direction) == 0 )
{
cyg_fp_free( fp );
FILEIO_RETURN(EBADF);
}
 
cyg_uio uio;
cyg_fileop_readwrite *op;
uio.uio_iov = iov;
uio.uio_iovcnt = iov_len;
uio.uio_resid = len;
uio.uio_segflg = UIO_USERSPACE;
 
cnt = len;
 
if( direction == O_RDONLY )
uio.uio_rw = UIO_READ, op = fp->f_ops->fo_read;
else
uio.uio_rw = UIO_WRITE, op = fp->f_ops->fo_write;
LOCK_FILE( fp );
ret = op( fp, &uio );
UNLOCK_FILE( fp );
cnt -= uio.uio_resid;
 
cyg_fp_free( fp );
 
CYG_CANCELLATION_POINT;
 
if( ret != 0 )
FILEIO_RETURN(ret);
FILEIO_RETURN_VALUE(cnt);
}
 
//==========================================================================
// Read from file
 
__externC ssize_t read( int fd, void *buf, size_t len )
{
cyg_iovec _iov;
 
_iov.iov_base = buf;
_iov.iov_len = len;
return readwritev(fd, &_iov, 1, O_RDONLY);
}
 
//==========================================================================
// Write to a file
 
__externC ssize_t write( int fd, const void *buf, size_t len )
{
cyg_iovec _iov;
 
_iov.iov_base = (void *)buf;
_iov.iov_len = len;
return readwritev(fd, &_iov, 1, O_WRONLY);
}
 
//==========================================================================
// Read via an iovec
__externC ssize_t readv( int fd, const cyg_iovec *_iov, int iov_len )
{
return readwritev(fd, _iov, iov_len, O_RDONLY);
}
 
//==========================================================================
// Write via an iovec
__externC ssize_t writev( int fd, const cyg_iovec *_iov, int iov_len )
{
return readwritev(fd, _iov, iov_len, O_WRONLY);
}
 
 
//==========================================================================
// Close a file
 
__externC int close( int fd )
{
FILEIO_ENTRY();
 
CYG_CANCELLATION_POINT;
int ret;
cyg_file *fp;
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
cyg_fp_free( fp );
// The file's fo_close entry may be called as a side
// effect of this operation...
ret = cyg_fd_free( fd );
 
CYG_CANCELLATION_POINT;
FILEIO_RETURN(ret);
}
 
//==========================================================================
// Seek a file
 
__externC off_t lseek( int fd, off_t pos, int whence )
{
FILEIO_ENTRY();
 
int ret;
cyg_file *fp;
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
LOCK_FILE( fp );
ret = fp->f_ops->fo_lseek( fp, &pos, whence );
 
UNLOCK_FILE( fp );
cyg_fp_free( fp );
 
if( ret != 0 )
FILEIO_RETURN(ret);
FILEIO_RETURN_VALUE(pos);
}
 
//==========================================================================
// ioctl
 
__externC int ioctl( int fd, CYG_ADDRWORD com, CYG_ADDRWORD data )
{
FILEIO_ENTRY();
 
int ret;
cyg_file *fp;
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
LOCK_FILE( fp );
ret = fp->f_ops->fo_ioctl( fp, com, data );
 
UNLOCK_FILE( fp );
cyg_fp_free( fp );
 
FILEIO_RETURN(ret);
}
 
//==========================================================================
// fsync
 
__externC int fsync( int fd )
{
FILEIO_ENTRY();
 
CYG_CANCELLATION_POINT;
int ret;
cyg_file *fp;
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
LOCK_FILE( fp );
ret = fp->f_ops->fo_fsync( fp, CYG_FSYNC );
 
UNLOCK_FILE( fp );
cyg_fp_free( fp );
 
CYG_CANCELLATION_POINT;
FILEIO_RETURN(ret);
}
 
//==========================================================================
// fdatasync()
 
__externC int fdatasync( int fd )
{
FILEIO_ENTRY();
 
CYG_CANCELLATION_POINT;
int ret;
cyg_file *fp;
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
LOCK_FILE( fp );
ret = fp->f_ops->fo_fsync( fp, CYG_FDATASYNC );
 
UNLOCK_FILE( fp );
cyg_fp_free( fp );
 
CYG_CANCELLATION_POINT;
FILEIO_RETURN(ret);
}
 
//==========================================================================
// fstat
 
__externC int fstat( int fd, struct stat *buf )
{
FILEIO_ENTRY();
 
int ret;
cyg_file *fp;
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
LOCK_FILE( fp );
ret = fp->f_ops->fo_fstat( fp, buf );
 
UNLOCK_FILE( fp );
cyg_fp_free( fp );
 
FILEIO_RETURN(ret);
}
 
//==========================================================================
// fpathconf
 
__externC long fpathconf( int fd, int name )
{
FILEIO_ENTRY();
 
int ret;
cyg_file *fp;
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
struct cyg_pathconf_info info;
 
info.name = name;
info.value = 0;
LOCK_FILE( fp );
ret = fp->f_ops->fo_getinfo( fp, FILE_INFO_CONF, (char *)&info, sizeof(info) );
 
UNLOCK_FILE( fp );
cyg_fp_free( fp );
 
if( ret != 0 )
FILEIO_RETURN(ret);
 
FILEIO_RETURN_VALUE(info.value);
}
 
//==========================================================================
// fcntl
 
__externC int fcntl( int fd, int cmd, ... )
{
FILEIO_ENTRY();
 
CYG_CANCELLATION_POINT;
int ret = 0;
cyg_file *fp;
va_list a;
 
fp = cyg_fp_get( fd );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
va_start( a, cmd );
switch( cmd )
{
case F_DUPFD:
{
int fda = va_arg(a, int);
 
if( fda < 0 || fda >= OPEN_MAX )
{
errno = EBADF;
break;
}
int fd2 = cyg_fd_alloc( fda );
 
if( fd2 == -1 )
{
ret = EMFILE;
break;
}
 
cyg_fd_assign( fd2, fp );
break;
}
default:
ret = ENOTSUP;
break;
}
 
va_end(a);
cyg_fp_free( fp );
CYG_CANCELLATION_POINT;
FILEIO_RETURN(ret);
}
 
//==========================================================================
// isatty()
 
__externC int isatty( int fd )
{
FILEIO_ENTRY();
 
int ret = 0;
struct stat buf;
int err;
 
err = fstat( fd, &buf );
 
// Any error and we return zero. If the client wants to
// they can always pick up the error code from errno.
if( err < 0 )
FILEIO_RETURN_VALUE(0);
 
// For now we assume that all char devices are ttys.
// In future we may need to have a special getinfo()
// call to decide this more specifically.
if( S_ISCHR( buf.st_mode ) )
ret = 1;
FILEIO_RETURN_VALUE(ret);
}
 
// -------------------------------------------------------------------------
// EOF io.cxx
/v2_0/src/socket.cxx
0,0 → 1,734
//==========================================================================
//
// socket.cxx
//
// Fileio socket 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 socket operations
// Description: These are the functions that operate on sockets,
// such as socket(), bind(), accept() etc.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/system.h>
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/hal/hal_tables.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include <stdarg.h> // for fcntl()
 
#include <cyg/io/file.h> // struct iovec
 
#include "fio.h" // Private header
 
#include <cyg/kernel/mutex.hxx> // mutex definitions
 
#ifdef CYGPKG_NET
 
#include <sys/socket.h> // struct msghdr
 
#endif
 
//==========================================================================
// Forward definitions
 
static void cyg_ns_lock( cyg_nstab_entry *ns );
static void cyg_ns_unlock( cyg_nstab_entry *ns );
static void cyg_sock_lock( cyg_file *fp );
static void cyg_sock_unlock( cyg_file *fp );
 
//==========================================================================
// Local entry/return macros
 
#define SOCKET_ENTRY() FILEIO_ENTRY()
 
#define SOCKET_RETURN(err) FILEIO_RETURN(err)
 
#define SOCKET_RETURN_VALUE(val) FILEIO_RETURN_VALUE(val)
 
//==========================================================================
// Locking protocols
 
#define LOCK_NS( _n ) cyg_ns_lock( _n )
 
#define UNLOCK_NS( _n ) cyg_ns_unlock( _n )
 
#define LOCK_SOCKET( _fp ) cyg_sock_lock( _fp )
 
#define UNLOCK_SOCKET( _fp ) cyg_sock_unlock( _fp )
 
//==========================================================================
// Tables and local variables
 
// Array of network stacks installed
__externC cyg_nstab_entry nstab[];
CYG_HAL_TABLE_BEGIN( nstab, nstab );
 
// End of array marker
__externC cyg_nstab_entry nstab_end;
CYG_HAL_TABLE_END( nstab_end, nstab );
 
Cyg_Mutex nstab_lock[CYGNUM_FILEIO_NSTAB_MAX];
 
//==========================================================================
// Initialization
 
__externC void cyg_nstab_init()
{
cyg_nstab_entry *n;
 
for( n = &nstab[0]; n != &nstab_end; n++ )
{
// stop if there are more than the configured maximum
if( n-&nstab[0] >= CYGNUM_FILEIO_NSTAB_MAX )
break;
 
if( n->init( n ) == 0 )
{
n->valid = true;
}
}
}
 
//==========================================================================
// Socket API calls
 
// -------------------------------------------------------------------------
 
__externC int socket (int domain, int type, int protocol)
{
SOCKET_ENTRY();
 
int err = 0;
int fd;
cyg_file *file;
 
fd = cyg_fd_alloc(0);
 
if( fd < 0 )
SOCKET_RETURN(EMFILE);
file = cyg_file_alloc();
 
if( file == NULL )
{
cyg_fd_free(fd);
SOCKET_RETURN(ENFILE);
}
 
cyg_nstab_entry *n;
 
for( n = &nstab[0]; n != &nstab_end; n++ )
{
LOCK_NS( n );
err = n->socket( n, domain, type, protocol, file );
 
UNLOCK_NS( n );
if( err == 0 ) break;
}
 
if( err != 0 )
{
cyg_fd_free(fd);
cyg_file_free(file);
SOCKET_RETURN( err );
}
 
file->f_syncmode = n->syncmode;
file->f_mte = (cyg_mtab_entry *)n;
cyg_fd_assign( fd, file );
 
SOCKET_RETURN_VALUE(fd);
}
 
 
// -------------------------------------------------------------------------
 
__externC int accept (int s, struct sockaddr *sa, socklen_t *addrlen)
{
SOCKET_ENTRY();
 
int err = 0;
int fd;
cyg_file *fp;
cyg_file *new_fp;
 
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
fd = cyg_fd_alloc(0);
 
if( fd < 0 )
{
cyg_fp_free( fp );
SOCKET_RETURN(EMFILE);
}
new_fp = cyg_file_alloc();
 
if( new_fp == NULL )
{
cyg_fp_free( fp );
cyg_fd_free(fd);
SOCKET_RETURN(ENFILE);
}
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
err = ops->accept( fp, new_fp, sa, addrlen );
 
UNLOCK_SOCKET( fp );
 
}
else err = EBADF;
 
if( err != 0 )
{
cyg_fp_free( fp );
cyg_fd_free(fd);
cyg_file_free(new_fp);
SOCKET_RETURN( err );
}
 
new_fp->f_syncmode = fp->f_syncmode;
new_fp->f_mte = fp->f_mte;
cyg_fd_assign( fd, new_fp );
 
cyg_fp_free( fp );
SOCKET_RETURN_VALUE(fd);
}
 
 
// -------------------------------------------------------------------------
 
__externC int bind (int s, const struct sockaddr *sa, unsigned int len)
{
SOCKET_ENTRY();
 
int ret = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
ret = ops->bind( fp, sa, len );
 
UNLOCK_SOCKET( fp );
 
}
cyg_fp_free( fp );
SOCKET_RETURN(ret);
}
 
 
// -------------------------------------------------------------------------
 
__externC int connect (int s, const struct sockaddr *sa, socklen_t len)
{
SOCKET_ENTRY();
 
int ret = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
ret = ops->connect( fp, sa, len );
 
UNLOCK_SOCKET( fp );
 
}
cyg_fp_free( fp );
SOCKET_RETURN(ret);
}
 
 
// -------------------------------------------------------------------------
 
__externC int getpeername (int s, struct sockaddr *sa, socklen_t *len)
{
SOCKET_ENTRY();
 
int ret = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
ret = ops->getname( fp, sa, len, 1 );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
SOCKET_RETURN(ret);
}
 
 
// -------------------------------------------------------------------------
 
__externC int getsockname (int s, struct sockaddr *sa, socklen_t *len)
{
SOCKET_ENTRY();
 
int ret = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
ret = ops->getname( fp, sa, len, 0 );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
SOCKET_RETURN(ret);
}
 
 
// -------------------------------------------------------------------------
 
__externC int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
{
SOCKET_ENTRY();
 
int ret = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
ret = ops->getsockopt( fp, level, optname, optval, optlen );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
SOCKET_RETURN(ret);
}
 
 
// -------------------------------------------------------------------------
 
__externC int listen (int s, int len)
{
SOCKET_ENTRY();
 
int ret = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
ret = ops->listen( fp, len );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
SOCKET_RETURN(ret);
}
 
 
// -------------------------------------------------------------------------
 
__externC ssize_t recvmsg (int s, struct msghdr *msg, int flags)
{
SOCKET_ENTRY();
 
ssize_t ret = 0;
int error = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
msg->msg_flags = flags;
error = ops->recvmsg( fp, msg, NULL, &ret );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
 
if( error != ENOERR )
SOCKET_RETURN(error);
 
SOCKET_RETURN_VALUE( ret );
}
 
// -------------------------------------------------------------------------
 
__externC ssize_t recvfrom (int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen)
{
SOCKET_ENTRY();
 
struct msghdr msg;
struct iovec iov;
ssize_t ret = 0;
int error = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
// Set up a message header...
msg.msg_name = (caddr_t)from;
msg.msg_namelen = fromlen ? *fromlen : 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_control = 0;
msg.msg_flags = flags;
 
LOCK_SOCKET( fp );
 
error = ops->recvmsg( fp, &msg, fromlen, &ret );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
 
if( error != ENOERR )
SOCKET_RETURN(error);
 
SOCKET_RETURN_VALUE( ret );
 
}
 
// -------------------------------------------------------------------------
 
__externC ssize_t recv (int s, void *buf, size_t len, int flags)
{
return recvfrom( s, buf, len, flags, NULL, NULL );
}
 
// -------------------------------------------------------------------------
 
__externC ssize_t sendmsg (int s, const struct msghdr *msg, int flags)
{
SOCKET_ENTRY();
 
ssize_t ret = 0;
int error = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
error = ops->sendmsg( fp, msg, flags, &ret );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
if( error != ENOERR )
SOCKET_RETURN(error);
 
SOCKET_RETURN_VALUE( ret );
}
 
 
// -------------------------------------------------------------------------
 
__externC ssize_t sendto (int s, const void *buf,
size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
{
SOCKET_ENTRY();
 
ssize_t ret = 0;
int error = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
struct msghdr msg;
struct iovec iov;
 
msg.msg_name = (caddr_t)to;
msg.msg_namelen = tolen;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = 0;
msg.msg_flags = 0;
iov.iov_base = (char *)buf;
iov.iov_len = len;
 
LOCK_SOCKET( fp );
 
error = ops->sendmsg( fp, &msg, flags, &ret );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
if( error != ENOERR )
SOCKET_RETURN(error);
 
SOCKET_RETURN_VALUE( ret );
}
 
// -------------------------------------------------------------------------
 
__externC ssize_t send (int s, const void *buf, size_t len, int flags)
{
return sendto( s, buf, len, flags, NULL, 0 );
}
 
 
// -------------------------------------------------------------------------
 
__externC int setsockopt (int s, int level, int optname,
const void *optval, socklen_t optlen)
{
SOCKET_ENTRY();
 
int ret = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
ret = ops->setsockopt( fp, level, optname, optval, optlen );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
SOCKET_RETURN(ret);
}
 
// -------------------------------------------------------------------------
 
__externC int shutdown (int s, int how)
{
SOCKET_ENTRY();
 
int ret = 0;
cyg_file *fp;
fp = cyg_fp_get( s );
 
if( fp == NULL )
FILEIO_RETURN(EBADF);
 
if( fp->f_type == CYG_FILE_TYPE_SOCKET )
{
cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops;
 
LOCK_SOCKET( fp );
 
ret = ops->shutdown( fp, how );
 
UNLOCK_SOCKET( fp );
}
cyg_fp_free( fp );
SOCKET_RETURN(ret);
}
 
//==========================================================================
// Locking protocol
 
static void cyg_ns_lock( cyg_nstab_entry *ns )
{
if( ns->syncmode & CYG_SYNCMODE_SOCK_NETSTACK )
{
nstab_lock[ns-&nstab[0]].lock();
}
}
 
static void cyg_ns_unlock( cyg_nstab_entry *ns )
{
if( ns->syncmode & CYG_SYNCMODE_SOCK_NETSTACK )
{
nstab_lock[ns-&nstab[0]].unlock();
}
}
 
static void cyg_sock_lock( cyg_file *fp )
{
cyg_nstab_entry *ns = (cyg_nstab_entry *)fp->f_mte;
 
if( fp->f_syncmode & CYG_SYNCMODE_SOCK_NETSTACK )
nstab_lock[ns-&nstab[0]].lock();
 
cyg_file_lock( fp, fp->f_syncmode>>CYG_SYNCMODE_SOCK_SHIFT);
}
 
static void cyg_sock_unlock( cyg_file *fp )
{
cyg_nstab_entry *ns = (cyg_nstab_entry *)fp->f_mte;
 
if( fp->f_syncmode & CYG_SYNCMODE_SOCK_NETSTACK )
nstab_lock[ns-&nstab[0]].unlock();
 
cyg_file_unlock( fp, fp->f_syncmode>>CYG_SYNCMODE_SOCK_SHIFT);
}
 
 
// -------------------------------------------------------------------------
// EOF socket.cxx
/v2_0/src/inocache.cxx
0,0 → 1,216
//=============================================================================
//
// inocache.cxx
//
// Implementation of inode cache
//
//=============================================================================
//####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): jlarmour
// Contributors:
// Date: 2002-01-18
// Purpose:
// Description:
// Usage:
// #include <cyg/fileio/inode.h>
// ...
//
//
//####DESCRIPTIONEND####
//
//=============================================================================
 
#include <pkgconf/system.h>
#include <cyg/infra/cyg_type.h>
#include <stdlib.h>
#include <cyg/fileio/inode.h>
 
#ifdef CYGPKG_KERNEL
# include <pkgconf/kernel.h>
# include <cyg/kernel/mutex.hxx>
# if 0
# define LOCK_ICACHE(_ic_) \
CYG_MACRO_START \
(_ic_)->icmutex.lock(); \
CYG_MACRO_END
 
# define UNLOCK_ICACHE(_ic_) \
CYG_MACRO_START \
(_ic_)->icmutex.unlock(); \
CYG_MACRO_END
# define LOCK_INO(_ic_,_ino_) \
CYG_MACRO_START \
(_ic_)->icmutex.lock(); \
CYG_MACRO_END
# define UNLOCK_INO(_ic_,_ino_) \
CYG_MACRO_START \
(_ic_)->icmutex.unlock(); \
CYG_MACRO_END
# endif
#endif
 
# define LOCK_ICACHE(_ic_) CYG_EMPTY_STATEMENT
# define UNLOCK_ICACHE(_ic_) CYG_EMPTY_STATEMENT
# define LOCK_INO(_ic_,_ino_) CYG_EMPTY_STATEMENT
# define UNLOCK_INO(_ic_,_ino_) CYG_EMPTY_STATEMENT
 
// Tried to make this implementation use tables, but the requirement to
// allow for extra space makes this difficult
 
__externC void
cyg_inodecache_destroy( cyg_inodecache *ic )
{
cyg_inode *tmp;
for ( tmp=ic->head; tmp != NULL; tmp=tmp->i_cache_next )
free(tmp);
#if CYGNUM_IO_FILEIO_MAX_INODE_CACHE_DEAD > 0
for ( tmp=ic->freeable; tmp != NULL; tmp=tmp->i_cache_next )
free(tmp);
#endif
} // cyg_inodecache_destroy()
 
static __inline__ void
insert_in_list( cyg_inode **i, cyg_inode *ino )
{
cyg_inode *here = *i;
if ( here == NULL ) {
ino->i_cache_prev = ino->i_cache_next = ino;
} else {
ino->i_cache_prev = here->i_cache_prev;
ino->i_cache_next = here;
here->i_cache_prev = ino;
ino->i_cache_prev->i_cache_next = ino;
}
// put at start, as this is more likely to come off sooner than later
*i = ino;
}
 
// Create an inode. Returns a negative error code on error.
__externC cyg_inode *
cyg_inode_create( cyg_inodecache *ic )
{
cyg_inode *ni;
 
ni = (cyg_inode *)malloc( sizeof(cyg_inode)+ic->privatespace );
if ( !ni )
return ni;
ni->i_count = 1;
 
LOCK_ICACHE(ic);
insert_in_list( &ic->head, ni );
UNLOCK_ICACHE(ic);
return ni;
} // cyg_inode_create()
 
__externC cyg_inode *
cyg_inode_get( cyg_inodecache *ic, cyg_uint32 ino )
{
cyg_inode *head = ic->head;
// first try the (live) cache
if (head) {
cyg_inode *tmp=head;
while (1) {
if ( tmp->i_ino == ino ) {
tmp->i_count++;
return tmp;
}
tmp = tmp->i_cache_next;
if ( tmp == head )
break;
}
}
#if CYGNUM_IO_FILEIO_MAX_INODE_CACHE_DEAD > 0
// now try the cache of dead inodes
head = ic->freeable;
if (head) {
cyg_inode *tmp=head;
while (1) {
if ( tmp->i_ino == ino ) {
tmp->i_count++;
LOCK_ICACHE(ic);
ic->freeablelistlen--;
if ( ic->freeablelistlen ) {
tmp->i_cache_prev->i_cache_next = tmp->i_cache_next;
tmp->i_cache_next->i_cache_prev = tmp->i_cache_prev;
} else
ic->freeable = NULL;
insert_in_list( &ic->head, tmp );
UNLOCK_ICACHE(ic);
return tmp;
}
tmp = tmp->i_cache_next;
if ( tmp == head )
break;
}
}
#endif
// not found so make it
return cyg_inode_create( ic );
} // cyg_inode_get()
 
__externC void
cyg_inode_put( cyg_inodecache *ic, cyg_inode *ino )
{
if ( --ino->i_count == 0 )
{
LOCK_ICACHE(ic);
if ( ino->i_cache_next == ino ) {
ic->head = NULL;
} else {
ino->i_cache_prev->i_cache_next = ino->i_cache_next;
ino->i_cache_next->i_cache_prev = ino->i_cache_prev;
}
#if CYGNUM_IO_FILEIO_MAX_INODE_CACHE_DEAD > 0
ic->freeablelistlen++;
insert_in_list( &ic->freeable, ino );
if ( ic->freeablelistlen > CYGNUM_IO_FILEIO_MAX_INODE_CACHE_DEAD ) {
cyg_inode *prev = ino->i_cache_prev;
prev->i_cache_prev->i_cache_next = ino;
ino->i_cache_prev = prev->i_cache_prev;
ic->freecallback(prev);
free(prev);
}
#else
ic->freecallback(ino);
free(ino);
#endif
}
} // cyg_inode_put()
 
// EOF inode.h
/v2_0/src/fd.cxx
0,0 → 1,383
//==========================================================================
//
// fd.cxx
//
// Fileio file descriptor implementation
//
//==========================================================================
//####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 descriptor implementation
// Description: This file contains the implementation of the file
// descriptor functions.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
 
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
 
#include "fio.h" // Private header
 
//-----------------------------------------------------------------------------
// File data structures
 
#ifdef CYGPKG_KERNEL
// Mutex for controlling access to file desriptor arrays
Cyg_Mutex fdlock CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
 
// Array of per-file mutexes
static Cyg_Mutex file_lock[CYGNUM_FILEIO_NFILE] \
CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
#endif // ifdef CYGPKG_KERNEL
 
// Array of open file objects
static cyg_file file[CYGNUM_FILEIO_NFILE];
 
// Descriptor array
static cyg_file *desc[CYGNUM_FILEIO_NFD];
 
#define FD_ALLOCATED ((cyg_file *)1)
 
//==========================================================================
// Initialization
 
__externC void cyg_fd_init()
{
int i;
 
for( i = 0; i < CYGNUM_FILEIO_NFILE; i++ )
file[i].f_flag = 0;
 
for( i = 0; i < CYGNUM_FILEIO_NFD; i++ )
desc[i] = NULL;
}
 
//==========================================================================
// File object allocation
 
//--------------------------------------------------------------------------
// Locate and allocate a free file object.
 
__externC cyg_file *cyg_file_alloc()
{
int i;
cyg_file *fp = NULL;
 
FILEIO_MUTEX_LOCK(fdlock);
 
for( i = 0; i < CYGNUM_FILEIO_NFILE; i++ )
{
if( (file[i].f_flag & CYG_FALLOC) == 0 )
{
fp = &file[i];
fp->f_flag = CYG_FALLOC;
fp->f_ucount = 0;
break;
}
}
 
FILEIO_MUTEX_UNLOCK(fdlock);
 
return fp;
}
 
//--------------------------------------------------------------------------
// Free a file object. This is a straightforward freeing, usually used
// during error recovery. File objects are normally freed as a side
// effect of cyg_fd_assign() or cyg_fd_free().
 
__externC void cyg_file_free(cyg_file * fp)
{
FILEIO_MUTEX_LOCK(fdlock);
 
fp->f_flag = 0;
FILEIO_MUTEX_UNLOCK(fdlock);
}
 
//==========================================================================
// Internal routines for handling descriptor deallocation
// These must all be called with the fdlock already locked.
 
//--------------------------------------------------------------------------
// Decrement the use count on a file object and if it goes to zero,
// close the file and deallocate the file object.
 
static int fp_ucount_dec( cyg_file *fp )
{
int error = 0;
if( (--fp->f_ucount) <= 0 )
{
cyg_file_lock( fp, fp->f_syncmode );
error = fp->f_ops->fo_close(fp);
 
cyg_file_unlock( fp, fp->f_syncmode );
if( error == 0 )
fp->f_flag = 0;
}
 
return error;
}
 
//--------------------------------------------------------------------------
// Clear out a descriptor. If this is the last reference to the file
// object, then that will be closed and deallocated.
 
static int fd_close( int fd )
{
int error = 0;
cyg_file *fp = desc[fd];
 
if( fp != FD_ALLOCATED && fp != NULL)
{
// The descriptor is occupied, decrement its usecount and
// close the file if it goes zero.
 
error = fp_ucount_dec( fp );
}
 
desc[fd] = FD_ALLOCATED;
 
return error;
}
 
 
//==========================================================================
// File descriptor allocation
 
//--------------------------------------------------------------------------
// Allocate a file descriptor. The allocated descriptor is set to the value
// FD_ALLOCATED to prevent it being reallocated by another thread.
 
__externC int cyg_fd_alloc(int low)
{
int fd;
 
FILEIO_MUTEX_LOCK(fdlock);
for( fd = low; fd < CYGNUM_FILEIO_NFD; fd++ )
{
if( desc[fd] == NULL )
{
desc[fd] = FD_ALLOCATED;
FILEIO_MUTEX_UNLOCK(fdlock);
return fd;
}
}
 
FILEIO_MUTEX_UNLOCK(fdlock);
 
return -1;
}
 
//--------------------------------------------------------------------------
// Assign a file object to a descriptor. If the descriptor is already
// occupied, the occupying files usecount is decrement and it may be
// closed.
 
__externC void cyg_fd_assign(int fd, cyg_file *fp)
{
FILEIO_MUTEX_LOCK(fdlock);
 
fd_close( fd );
 
fp->f_ucount++;
desc[fd] = fp;
 
FILEIO_MUTEX_UNLOCK(fdlock);
}
 
//--------------------------------------------------------------------------
// Free a descriptor. Any occupying files usecount is decremented and
// it may be closed.
 
__externC int cyg_fd_free(int fd)
{
int error;
FILEIO_MUTEX_LOCK(fdlock);
error = fd_close( fd );
 
desc[fd] = NULL;
FILEIO_MUTEX_UNLOCK(fdlock);
 
return error;
}
 
//==========================================================================
// Descriptor to file object mapping
 
 
//--------------------------------------------------------------------------
// Map a descriptor to a file object. This is just a straightforward index
// into the descriptor array complicated by the need to lock the mutex and
// increment the usecount.
 
__externC cyg_file *cyg_fp_get( int fd )
{
FILEIO_MUTEX_LOCK(fdlock);
cyg_file *fp = desc[fd];
 
if( fp != FD_ALLOCATED && fp != NULL)
{
// Increment use count while we work on this file
fp->f_ucount++;
}
else fp = NULL;
FILEIO_MUTEX_UNLOCK(fdlock);
 
return fp;
}
 
//--------------------------------------------------------------------------
// Free the usecount reference we acquired in cyg_fp_get(). If the usecount
// is zeroed, the file will be closed.
 
__externC void cyg_fp_free( cyg_file *fp )
{
FILEIO_MUTEX_LOCK(fdlock);
 
fp_ucount_dec( fp );
FILEIO_MUTEX_UNLOCK(fdlock);
}
 
//==========================================================================
// File locking protocol
 
void cyg_file_lock( cyg_file *fp , cyg_uint32 syncmode )
{
cyg_fs_lock( fp->f_mte, syncmode>>CYG_SYNCMODE_IO_SHIFT);
 
if( syncmode & CYG_SYNCMODE_IO_FILE )
{
fp->f_flag |= CYG_FLOCKED;
FILEIO_MUTEX_LOCK(file_lock[fp-&file[0]]);
}
}
 
void cyg_file_unlock( cyg_file *fp, cyg_uint32 syncmode )
{
cyg_fs_unlock( fp->f_mte, syncmode>>CYG_SYNCMODE_IO_SHIFT);
 
if( syncmode & CYG_SYNCMODE_IO_FILE )
{
fp->f_flag &= ~CYG_FLOCKED;
FILEIO_MUTEX_UNLOCK(file_lock[fp-&file[0]]);
}
}
 
 
//==========================================================================
// POSIX API routines
 
//--------------------------------------------------------------------------
// dup() - duplicate an FD into a random descriptor
 
__externC int dup( int fd )
{
cyg_file *fp = cyg_fp_get( fd );
 
if( fp == NULL )
{
errno = EBADF;
return -1;
}
int fd2 = cyg_fd_alloc(0);
 
if( fd2 == -1 )
{
errno = EMFILE;
return -1;
}
 
cyg_fd_assign( fd2, fp );
cyg_fp_free(fp);
 
return fd2;
}
 
//--------------------------------------------------------------------------
// dup2() - duplicate an FD into a chosen descriptor
 
__externC int dup2( int fd, int fd2 )
{
if( fd2 == fd ) return fd2;
if( fd2 < 0 || fd2 >= OPEN_MAX )
{
errno = EBADF;
return -1;
}
 
cyg_file *fp = cyg_fp_get( fd );
 
if( fp == NULL )
{
errno = EBADF;
return -1;
}
 
cyg_fd_assign( fd2, fp );
cyg_fp_free(fp);
 
return fd2;
}
 
// -------------------------------------------------------------------------
// EOF fd.cxx
/v2_0/src/misc.cxx
0,0 → 1,478
//==========================================================================
//
// misc.cxx
//
// Fileio miscellaneous functions
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2003 Gary Thomas
//
// 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 miscellaneous functions
// Description: This file contains various miscellaneous functions
// for use with the fileio system. These include startup,
// table management, and other service routines.
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <pkgconf/system.h>
#include <pkgconf/hal.h>
#include <pkgconf/io_fileio.h>
#ifdef CYGPKG_LIBC_TIME
#include <pkgconf/libc_time.h>
#endif
 
 
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
#include <string.h> // strcmp()
#include <time.h> // time()
 
#ifdef CYGPKG_IO_WALLCLOCK
# include <cyg/io/wallclock.hxx> // Wallclock class
#endif
 
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/kernel/clock.inl> // Clock inlines
#endif
 
#include "fio.h" // Private header
 
//==========================================================================
// forward definitions
 
static void cyg_mtab_init();
 
__externC int chdir( const char *path );
 
//==========================================================================
// Filesystem tables
 
// -------------------------------------------------------------------------
// Filesystem table.
 
// This array contains entries for all filesystem that are installed in
// the system.
__externC cyg_fstab_entry fstab[];
CYG_HAL_TABLE_BEGIN( fstab, fstab );
 
// end of filesystem table, set in linker script.
__externC cyg_fstab_entry fstab_end;
CYG_HAL_TABLE_END( fstab_end, fstab );
 
#ifdef CYGPKG_KERNEL
// Array of mutexes for locking the fstab entries
Cyg_Mutex fstab_lock[CYGNUM_FILEIO_FSTAB_MAX] CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
#endif
 
// -------------------------------------------------------------------------
// Mount table.
 
// This array contains entries for all valid running filesystems.
__externC cyg_mtab_entry mtab[];
CYG_HAL_TABLE_BEGIN( mtab, mtab );
 
// Extra entries at end of mtab for dynamic mount points.
cyg_mtab_entry mtab_extra[CYGNUM_FILEIO_MTAB_EXTRA] CYG_HAL_TABLE_EXTRA(mtab) = { { NULL } };
 
// End of mount table, set in the linker script.
__externC cyg_mtab_entry mtab_end;
CYG_HAL_TABLE_END( mtab_end, mtab );
 
#ifdef CYGPKG_KERNEL
// Array of mutexes for locking the mtab entries
Cyg_Mutex mtab_lock[CYGNUM_FILEIO_MTAB_MAX] CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
#endif
 
//==========================================================================
// Current directory
 
cyg_mtab_entry *cdir_mtab_entry = NULL;
cyg_dir cdir_dir = CYG_DIR_NULL;
 
//==========================================================================
// Initialization object
 
class Cyg_Fileio_Init_Class
{
public:
Cyg_Fileio_Init_Class();
};
 
static Cyg_Fileio_Init_Class fileio_initializer CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
 
Cyg_Fileio_Init_Class::Cyg_Fileio_Init_Class()
{
cyg_fd_init();
 
cyg_mtab_init();
 
chdir("/");
}
 
//==========================================================================
// Mount table initializer
 
static void cyg_mtab_init()
{
cyg_mtab_entry *m;
for( m = &mtab[0]; m != &mtab_end; m++ )
{
const char *fsname = m->fsname;
cyg_fstab_entry *f;
 
// Ignore empty entries
if( m->name == NULL )
continue;
// stop if there are more than the configured maximum
if( m-&mtab[0] >= CYGNUM_FILEIO_MTAB_MAX )
break;
for( f = &fstab[0]; f != &fstab_end; f++ )
{
// stop if there are more than the configured maximum
if( f-&fstab[0] >= CYGNUM_FILEIO_FSTAB_MAX )
break;
if( strcmp( fsname, f->name) == 0 )
{
// We have a match.
 
if( f->mount( f, m ) == 0 )
{
m->valid = true;
m->fs = f;
// m->root installed by fs.
}
else
{
m->valid = false;
}
break;
}
}
}
}
 
//==========================================================================
// Mount table matching
 
// -------------------------------------------------------------------------
// matchlen() compares two strings and returns the number of bytes by which
// they match.
 
static int matchlen( const char *s1, const char *s2 )
{
int len = 0;
while( s1[len] == s2[len] && s1[len] && s2[len] ) len++;
 
// Return length only if s2 is an initial substring of s1,
// and it terminates in s1 at end-of-string or a '/'.
 
// Special case for s2 == "/"
if( len == 1 && s2[0] == '/' && s2[1] == 0 )
return len;
if( (s2[len] == 0) && (s1[len] == 0 || s1[len] == '/'))
return len;
else return 0;
}
 
// -------------------------------------------------------------------------
// Search the mtab for the entry that matches the longest substring of
// **name.
 
__externC int cyg_mtab_lookup( cyg_dir *dir, const char **name, cyg_mtab_entry **mte)
{
cyg_mtab_entry *m, *best = NULL;
int best_len = 0;
 
// Unrooted file names go straight to current dir
if( **name != '/' ) {
if (*mte == (cyg_mtab_entry *)NULL) {
// No known current directory
return -1;
}
// Current directory is well known
return 0;
}
 
// Otherwise search the mount table.
for( m = &mtab[0]; m != &mtab_end; m++ )
{
if( m->name != NULL && m->valid )
{
int len = matchlen(*name,m->name);
if( len > best_len )
best = m, best_len = len;
}
}
 
// No match found, bad path name...
if( best_len == 0 ) return -1;
*name += best_len;
if( **name == '/' )
(*name)++;
*mte = best;
*dir = best->root;
 
return 0;
}
 
//==========================================================================
// mount filesystem
 
__externC int mount( const char *devname,
const char *dir,
const char *fsname)
{
 
FILEIO_ENTRY();
cyg_mtab_entry *m;
cyg_fstab_entry *f;
int result = ENOERR;
 
// Search the mount table for an empty entry
for( m = &mtab[0]; m != &mtab_end; m++ )
{
// stop if there are more than the configured maximum
if( m-&mtab[0] >= CYGNUM_FILEIO_MTAB_MAX )
{
m = &mtab_end;
break;
}
 
if( m->name == NULL ) break;
}
 
if( m == &mtab_end )
FILEIO_RETURN(ENOMEM);
 
// Now search the fstab for the filesystem implementation
for( f = &fstab[0]; f != &fstab_end; f++ )
{
// stop if there are more than the configured maximum
if( f-&fstab[0] >= CYGNUM_FILEIO_FSTAB_MAX )
break;
if( strcmp( fsname, f->name) == 0 )
break;
}
 
if( f == &fstab_end )
FILEIO_RETURN(ENODEV);
// We have a match.
 
m->name = dir;
m->fsname = fsname;
m->devname = devname;
if( (result = f->mount( f, m )) == 0 )
{
m->valid = true;
m->fs = f;
// m->root installed by fs.
}
else
{
m->valid = false;
m->name = NULL;
}
 
// Make sure that there is something to search (for open)
 
if (cdir_mtab_entry == (cyg_mtab_entry *)NULL) {
cdir_mtab_entry = m;
}
 
FILEIO_RETURN(result);
}
 
//==========================================================================
// unmount filesystem
 
__externC int umount( const char *name)
{
int err = ENOERR;
FILEIO_ENTRY();
cyg_mtab_entry *m;
 
// Search the mount table for a matching entry
for( m = &mtab[0]; m != &mtab_end; m++ )
{
// stop if there are more than the configured maximum
if( m-&mtab[0] >= CYGNUM_FILEIO_MTAB_MAX )
{
m = &mtab_end;
break;
}
 
// Ignore empty or invalid entries
if( m->name == NULL || !m->valid ) continue;
 
// match names.
if( strcmp(name,m->name) == 0 ) break;
 
// Match device name too?
}
 
if( m == &mtab_end )
FILEIO_RETURN(EINVAL);
 
// We have a match, call the umount function
 
err = m->fs->umount( m );
 
if( err == ENOERR )
{
m->valid = false;
m->name = NULL;
}
FILEIO_RETURN(err);
}
 
//==========================================================================
// Implement filesystem locking protocol.
 
void cyg_fs_lock( cyg_mtab_entry *mte, cyg_uint32 syncmode )
{
CYG_ASSERT(mte != NULL, "Bad mount table entry");
 
if( syncmode & CYG_SYNCMODE_FILE_FILESYSTEM ) {
CYG_ASSERT(mte->fs-&fstab[0] < CYGNUM_FILEIO_FSTAB_MAX, "Bad file system");
FILEIO_MUTEX_LOCK( fstab_lock[mte->fs-&fstab[0]] );
}
 
if( syncmode & CYG_SYNCMODE_FILE_MOUNTPOINT ) {
CYG_ASSERT(mte-&mtab[0] < CYGNUM_FILEIO_MTAB_MAX, "Bad mount point");
FILEIO_MUTEX_LOCK( mtab_lock[mte-&mtab[0]] );
}
}
 
void cyg_fs_unlock( cyg_mtab_entry *mte, cyg_uint32 syncmode )
{
CYG_ASSERT(mte != NULL, "Bad mount table entry");
 
if( syncmode & CYG_SYNCMODE_FILE_FILESYSTEM ) {
CYG_ASSERT(mte->fs-&fstab[0] < CYGNUM_FILEIO_FSTAB_MAX, "Bad file system");
FILEIO_MUTEX_UNLOCK( fstab_lock[mte->fs-&fstab[0]] );
}
 
if( syncmode & CYG_SYNCMODE_FILE_MOUNTPOINT ) {
CYG_ASSERT(mte-&mtab[0] < CYGNUM_FILEIO_MTAB_MAX, "Bad mount point");
FILEIO_MUTEX_UNLOCK( mtab_lock[mte-&mtab[0]] );
}
}
 
//==========================================================================
// Timestamp support
// This provides access to the current time/date, expressed as a
// time_t. It uses a number of mechanisms to do this, selecting
// whichever is available in the current configuration.
 
__externC time_t cyg_timestamp()
{
#if defined(CYGPKG_IO_WALLCLOCK)
 
// First, try to get the time from the wallclock device.
return (time_t) Cyg_WallClock::wallclock->get_current_time();
 
#elif defined(CYGINT_ISO_POSIX_TIMERS)
 
// If POSIX is present, use the current value of the realtime
// clock.
struct timespec tp;
 
clock_gettime( CLOCK_REALTIME, &tp );
 
return (time_t) tp.tv_sec;
#elif defined(CYGPKG_KERNEL)
 
// If all else fails, get the current realtime clock value and
// convert it to seconds ourself.
static struct Cyg_Clock::converter sec_converter;
static cyg_bool initialized = false;
cyg_tick_count ticks;
if( !initialized )
{
Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1000000000, &sec_converter );
initialized = true;
}
 
ticks = Cyg_Clock::real_time_clock->current_value();
return (time_t) Cyg_Clock::convert( ticks, &sec_converter );
#else
/* No clock support at all. */
return (time_t) 0;
#endif
}
 
//==========================================================================
// Default functions
 
__externC int cyg_fileio_enosys() { return ENOSYS; }
__externC int cyg_fileio_erofs() { return EROFS; }
__externC int cyg_fileio_enoerr() { return ENOERR; }
__externC int cyg_fileio_enotdir() { return ENOTDIR; }
 
__externC int cyg_fileio_seltrue (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info)
{ return 1; }
 
// -------------------------------------------------------------------------
// EOF misc.cxx
/v2_0/ChangeLog
0,0 → 1,623
2003-02-24 Jonathan Larmour <jifl@eCosCentric.com>
 
* cdl/fileio.cdl: Add doc link.
 
2003-02-20 Bart Veer <bartv@ecoscentric.com>
 
* cdl/fileio.cdl: identify test binaries, not test sources
 
2003-01-30 Andrew Lunn <andrew.lunn@ascom.ch>
 
* cdl/fileio.cdl: Added interface CYGINT_IO_FILEIO_FS which any
FS which FILEIO can use should implement.
 
2003-01-23 Gary Thomas <gary@mlbassoc.com>
 
* src/misc.cxx (cyg_mtab_lookup): Return an error if the current
directory is not known - happens if no file systems are mounted.
 
2002-11-10 Nick Garnett <nickg@ecoscentric.com>
 
* src/fio.h: Added macros to deal with signal handling. These will
call into the POSIX package if it is present, but are null if it
is not.
 
* src/select.cxx: Renamed original select() to cyg_pselect() and
added select() and pselect() routine from POSIX-200X to call
it. Reorganized code a little and added calls to macros to deal
with signal delivery and detection.
 
* cdl/fileio.cdl:
* tests/pselect.c: New test added to verify the signal masking and
delivery behaviour of pselect().
 
* tests/select.c: Fixed up some printfs to make it a little tidier.
 
2002-11-03 Gary Thomas <gthomas@ecoscentric.com>
 
* src/io.cxx:
* cdl/fileio.cdl: Add readv()/writev() support.
 
2002-08-08 Nick Garnett <nickg@calivar.demon.co.uk>
 
* src/select.cxx (select): Changed mechanism for calculating
select timeout to avoid possible race conditions between this code
and the timer DSR.
 
2002-05-29 Jesper Skov <jskov@redhat.com>
 
* tests/fileio1.c: Removed strcat definition. Rely on string.h to
provide it.
 
2002-05-28 Jonathan Larmour <jlarmour@redhat.com>
 
* include/limits.h (NAME_MAX): Increase default to 64.
* cdl/fileio.cdl: Set CYGBLD_ISO_NAME_MAX_HEADER.
 
2002-04-11 Nick Garnett <nickg@redhat.com>
 
* doc/fileio.sgml: Added a section on writing a new
filesystem. This probably still needs more work, but it's better
than nothing.
 
2002-04-05 Nick Garnett <nickg@redhat.com>
 
* src/devfs.cxx: Changed test for EAGAIN in dev_fo_read() and
dev_fo_write() to negate value first.
 
2002-03-07 Nick Garnett <nickg@redhat.com>
 
* doc/fileio.sgml: Added this file to contain documentation on
this package.
 
2002-02-04 Gary Thomas <gthomas@redhat.com>
 
* tests/socket.c (main):
* tests/select.c (main): sin_len field must be set.
 
2002-01-29 Jonathan Larmour <jlarmour@redhat.com>
 
* cdl/fileio.cdl: Actually, don't bother to build testfs.c at all.
 
2002-01-29 Jesper Skov <jskov@redhat.com>
 
* cdl/fileio.cdl: Added CYGPKG_FILEIO_BUILD_TESTS option and made
building of testfs dependant on it.
 
2002-01-25 Jonathan Larmour <jlarmour@redhat.com>
 
* include/inode.h: New API defining a common generic inode type.
* src/inocache.cxx: Implement the inode cache functions.
* cdl/fileio.cdl: (Configurably) build it.
 
2002-01-23 David Woodhouse <dwmw2@redhat.com>
2002-01-23 Jonathan Larmour <jlarmour@redhat.com>
 
* cdl/fileio.cdl: Remove select compilation and support to new
CYGFUN_IO_FILEIO_SELECT option conditional on the kernel
Ditto for DEVS and CYGPKG_IO_FILEIO_DEVFS_SUPPORT.
Make CYGPKG_IO_FILEIO_SOCKET_SUPPORT also conditional on kernel.
* src/fio.h: Define FILEIO_MUTEX_LOCK() and FILEIO_MUTEX_UNLOCK()
so that code doesn't need to care whether the kernel is included or
not.
* src/fd.cxx: Conditionalize mutex usage throughout on CYGPKG_KERNEL,
and FILEIO_MUTEX_LOCK()/UNLOCK().
* src/file.cxx: Ditto.
* src/misc.cxx: Ditto.
(cyg_timestamp): Only use Cyg_Clock implementation if CYGPKG_KERNEL.
 
2002-01-23 Jonathan Larmour <jlarmour@redhat.com>
 
* src/misc.cxx: Initialize fileio_initializer at prio CYG_INIT_IO_FS
so it happens after the devices it depends on.
* src/file.cxx (getcwd_lock): Ditto.
* src/select.cxx (select_mutex): ditto.
(selwait): ditto.
* src/fd.cxx (fdlock): ditto
(file_lock): ditto.
* src/dir.cxx (readdir): Use FILEIO_RETURN_VALUE on exit.
(readdir_r): Ditto.
* src/devfs.cxx (dev_stat): Don't use handle for st_dev - it will
probably be truncated.
 
2002-01-04 Wade Jensen <Wade_Jensen@inter-tel.com>
2002-01-04 Jonathan Larmour <jlarmour@redhat.com>
 
* src/socket.cxx (recvfrom): Set msg.msg_namelen correctly for
NULL fromlen.
 
2001-12-28 Gary Thomas <gthomas@redhat.com>
 
* src/io.cxx (readwrite): Add missing check for return (errors).
 
2001-11-29 Jonathan Larmour <jlarmour@redhat.com>
 
* src/file.cxx (chdir): Don't detach from current dir if unset.
 
2001-11-02 Felix Wong <felixwong@i-technologies.cc>
2001-11-02 Jonathan Larmour <jlarmour@redhat.com>
 
* src/devfs.cxx (dev_fo_read): Support block devices.
(dev_fo_write): Ditto.
 
2001-10-09 Jonathan Larmour <jlarmour@redhat.com>
 
* src/fio.h: Make cancellation point dependand on
CYGINT_ISO_PTHREAD_IMPL from <pkgconf/isoinfra.h> really.
* tests/select.c: Ditto.
 
2001-10-09 Jesper Skov <jskov@redhat.com>
 
* tests/select.c: Do NA check for posix threads.
 
* src/fio.h: Make cancellation point dependant on
CYGPKG_POSIX_PTHREAD as in the POSIX package.
 
2001-07-26 Jonathan Larmour <jlarmour@redhat.com>
 
* cdl/fileio.cdl: Implements select().
* src/select.cxx: Include <sys/select.h> from isoinfra.
 
2001-07-19 Jonathan Larmour <jlarmour@redhat.com>
 
* src/devfs.cxx (dev_fo_read): Treat non-blocking reads returning
EAGAIN correctly
(dev_fo_write): Ditto for writes.
 
2001-06-14 Jonathan Larmour <jlarmour@redhat.com>
 
* src/fio.h (FILEIO_ENTRY): Don't use CYG_MACRO_START/END around
tracing macros.
Reported by Richard Panton.
 
2001-06-11 Jonathan Larmour <jlarmour@redhat.com>
 
* src/socket.cxx (cyg_sock_unlock): Fix cyg_file_lock->cyg_file_unlock
thinko.
 
2001-03-15 Gary Thomas <gthomas@redhat.com>
 
* src/file.cxx (open): Check for required/valid open mode.
 
2001-03-14 Jonathan Larmour <jlarmour@redhat.com>
 
* src/misc.cxx (cyg_mtab_lookup): check valid mtab entry
(umount): ditto.
 
2001-03-14 Martin van Veen <martin_van_veen@yahoo.com>
 
* src/misc.cxx (mount): Return error if mount fails.
 
2001-03-12 Gary Thomas <gthomas@redhat.com>
 
* src/misc.cxx (mount): Do implicit 'chdir()' in the
absence of any statically mounted file systems.
(cyg_fs_lock, cyg_fs_unlock): Add assertions.
 
* src/file.cxx (LOCK_FS):
* src/dir.cxx (LOCK_FS): Add assertions on 'mte'.
 
2001-01-05 Nick Garnett <nickg@cygnus.co.uk>
 
* tests/socket.c (main):
Added call to init_all_network_interfaces().
 
2000-12-15 Nick Garnett <nickg@cygnus.co.uk>
 
* src/misc.cxx: Fixed some bugs in initialization of timestamp
function when Wallclock and POSIX packages are absent.
 
2000-11-01 Jonathan Larmour <jlarmour@redhat.com>
 
* src/io.cxx (readwrite): Ensure we call FILEIO_RETURN_VALUE() to
get correct cleanup
(fpathconf): Ditto
(lseek): Ditto
 
* src/file.cxx (open): If applicable, refer to stdin, stdout and stderr
here to ensure they are pulled in, in case selective linking would
otherwise eliminate them. This is to ensure they get allocated to
fd's 0, 1 and 2.
 
2000-10-13 Nick Garnett <nickg@cygnus.co.uk>
 
* src/io.cxx (readwrite): Merged both read() and write() functions
into this single common routine.
 
* include/fileio.h: Introduced a common typedef for both read and
write operations.
 
* doc/fileio.txt: Added some text about getcwd() and tidied up
some other parts.
 
2000-10-05 Nick Garnett <nickg@cygnus.co.uk>
 
* src/file.cxx: Added support for getcwd(). There are three
mechanisms provided here. The first is to use the FS_INFO_GETCWD
key on the filesystem to use any support it has for this. If that
fails it falls back on one of the two other mechanisms. If
CYGPKG_IO_FILEIO_TRACK_CWD is set then the current directory is
tracked textually in chdir() and the result of that is reported in
getcwd(). Otherwise an attempt is made to traverse the directory
tree to its root using ".." entries. This last option is
complicated and expensive, so the other two mechanisms are to be
preferred if possible.
 
* include/fileio.h: Added FS_INFO_GETCWD getinfo option and a
matching struct cyg_getcwd_info. These are used to access getcwd()
support in a filesystem.
 
* src/fio.h: Added initial support for POSIX API function entry
and return.
 
* cdl/fileio.cdl: Added CYGPKG_IO_FILEIO_TRACK_CWD option to
enable current directory tracking.
 
2000-09-28 Nick Garnett <nickg@cygnus.co.uk>
 
* src/select.cxx (cyg_selwakeup):
Removed test for whether the waiting thread is actually waiting
for this event. This lead to a race condition when the thread is
still polling other objects but has already checked this
event. Now all waiting selectors are woken up by each selectable
event.
 
2000-09-18 Jonathan Larmour <jlarmour@redhat.com>
 
* src/select.cxx: Apply constructor prioritization to mutexes and
condition variables
* src/fd.cxx: Ditto
 
2000-09-11 Jonathan Larmour <jlarmour@redhat.com>
 
* tests/select.c: NA if no POSIX package
 
* cdl/fileio.cdl: Set CYGBLD_ISO_OPEN_MAX_HEADER to this package's
limits.h
* include/limits.h: New file to define OPEN_MAX (and other things in
future)
 
2000-09-08 Nick Garnett <nickg@cygnus.co.uk>
 
* include/fileio.h:
Removed spaces from arguments to CYG_HAL_TABLE_ENTRY().
 
2000-09-04 Jonathan Larmour <jlarmour@redhat.com>
 
* include/sockio.h (struct cyg_nstab_entry): Apply CYG_HAL_TABLE_TYPE
* include/fileio.h (struct cyg_mtab_entry): Ditto
(FSTAB_ENTRY): Ditto
 
2000-08-31 Nick Garnett <nickg@cygnus.co.uk>
 
* src/select.cxx (select): Added scheduler unlock in timeout
return case.
 
2000-08-22 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* doc/fileio.txt: Add Nick's text description of plug-in filesystems
and sockets here for now.
 
2000-08-18 Nick Garnett <nickg@cygnus.co.uk>
 
* include/fileio.h: Added CYG_FAPPEND flag for preservation in
file object flags.
Added prototype for cyg_timestamp().
 
* src/misc.cxx: Fixed bug in cyg_mtab_lookup() when dealing with
empty mount table entries.
Added cyg_timestamp() to provide timestamp support to client
filesystems.
 
2000-08-09 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* src/misc.cxx: Don't define own strcmp() function (which had a bug
anyway). Use string.h.
* cdl/fileio.cdl: requires ISO C string functions
 
2000-08-01 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* src/misc.cxx: Use correct initializer for mtab_extra
 
* src/fio.h (FILEIO_RETURN_VOID): Surround in CYG_MACRO_START to
prevent problems when used with one-line if.
(FILEIO_RETURN_VALUE): Likewise
 
* include/fileio.h: Make getinfo/setinfo take void *bufs, not char *
for easier casting (and more correct)
 
* tests/testfs.c: Likewise
 
* src/devfs.cxx: Likewise.
Also fix bug with Nick's change below that set non-blocking mode
in all cases.
 
2000-07-31 Nick Garnett <nickg@cygnus.co.uk>
 
* src/devfs.cxx (dev_open): Added support for O_NONBLOCK.
 
2000-07-27 Nick Garnett <nickg@cygnus.co.uk>
 
* tests/select.c: Wrapped include of pkgconf/io_serial.h in
#ifdef CYGPKG_IO_SERIAL.
 
2000-07-25 Jonathan Larmour <jlarmour@redhat.co.uk>
 
* tests/select.c (main): Wrap call to init_all_network_interfaces()
in #ifdef TEST_NET
 
2000-07-25 Nick Garnett <nickg@cygnus.co.uk>
 
* tests/select.c (main): Added call to
init_all_network_interfaces().
 
2000-07-21 Nick Garnett <nickg@cygnus.co.uk>
 
* include/fileio.h:
* src/file.cxx:
* src/devfs.cxx:
* tests/testfs.c:
Added support for link() API call. This was the only major file
operation omitted.
 
2000-07-20 Nick Garnett <nickg@cygnus.co.uk>
 
* include/fileio.h: Added some modes for fsync().
 
* src/file.cxx: Added access() function.
 
* src/io.cxx: Added fdatasync() and isatty().
 
* src/devfs.cxx: Added fsync() support.
 
* tests/fileio1.c: Added calls to access() to check (non-)existence
of files where appropriate.
 
2000-07-13 Nick Garnett <nickg@cygnus.co.uk>
 
* src/select.cxx (select): Fixed return value when timing out. Now
returns zero and no error, it used to return -1 and ETIMEDOUT.
 
* src/io.cxx: Fixed fsync() to match standard.
 
* src/devfs.cxx:
Added lseek() support - all devices are always at position
zero. Added [f]stat() support - currently just fills in the stat
buffer with some predefined values. When we have more
sophisticated devices this may need to be improved.
 
* tests/testfs.c (testfs_open): Added support for O_TRUNC open
flag.
* tests/stdio.c:
* cdl/fileio.cdl:
Added stdio.c to test C library IO integration. This does not test
the C library functionality, just that it works with the fileio
package in certain limited ways.
 
2000-06-30 Nick Garnett <nickg@cygnus.co.uk>
 
* src/misc.cxx: Fixed definition of mtab_extra[] so that it gets
emitted correctly into the object file.
 
* tests/testfs.c:
Added support for dynamic mount()/umount().
Added testfs_dump() to report state of filesystem, and to do a
little consistency checking.
 
* tests/fileio1.c: Extended testing to mount() and maximum file
sizes.
 
2000-06-28 Nick Garnett <nickg@cygnus.co.uk>
 
* include/dirent.h: Added this file to contain directory support
definitions.
 
* include/fileio.h:
Introduced separate typedefs for all operation functions.
Added CYG_FDIR to mark directory streams.
Added some default operation functions.
 
* src/fio.h (FILEIO_RETURN_VOID): Added this macro.
 
* src/dir.cxx: Added this file to contain directory listing API
functions.
 
* src/misc.cxx:
Added default operation functions.
 
* src/file.cxx:
Fixed mkdir() to have correct prototype.
Moved opendir() to dir.cxx.
Added support in chdir() for deregistering the current directory.
 
* cdl/fileio.cdl: Added dev.cxx to compile list. Added support for
dirent.h implementation.
 
* tests/testfs.c: Lots of changes towards a more complete
implementation.
 
* tests/select.c: Changed SHOW_RESULT() message a little. Fixed up
some warnings when no testing is possible.
 
* tests/fileio1.c:
Largely rewritten to do more complete testing.
 
2000-06-19 Nick Garnett <nickg@cygnus.co.uk>
 
* src/select.cxx: Added selwake_count variable to count select
wakeups. This allows us to avoid sleeping when a selectee calls
cyg_selwakeup() while we are still scanning the FD sets.
 
* include/fileio.h:
* include/sockio.h:
* src/misc.cxx:
* src/socket.cxx:
Converted tables to new mechanism.
 
* tests/select.c: Reduced buffer size to avoid buffer overflow in
serial devices.
2000-06-15 Nick Garnett <nickg@cygnus.co.uk>
 
* include/fileio.h:
Added typedef for cyg_selinfo.
Added umount to fstab entry structure.
Added mount() and unmount() prototypes.
Added const in various places.
Changed some types from CYG_ADDRWORD to their ISO standard
equivalents.
Added si_thread field to cyg_selinfo structure, added
cyg_selinit() prototype.
 
* src/socket.cxx: Converted an errant LOCK_NS() into the
UNLOCK_NS() it should be.
 
* src/select.cxx:
Added cyg_selinit() which must be called by all selectees at
initialization to prepare a cyg_selinfo structure for use.
Modified cyg_selwakeup() to minimize the number for actual wakeup
operations it actually performs.
 
* src/misc.cxx:
Added mtab_extra[] to contain dynamic mount table entries,
modified startup scan of mtab to cope with this.
changed matchlen() to cope with "/" mountpoint, this function is
rapidly ceasing to be the neat bit of code it started out as.
Added implementations of mount() and umount().
 
* src/devfs.cxx: Added dev_umount, various minor tweaks.
 
* cdl/fileio.cdl: Added CYGNUM_FILEIO_MTAB_EXTRA to define how
many extra mount table entries should exist for dynamic mounts.
Added select.c to list of tests.
 
* tests/select.c: Added this file to test select() functionality
on both sockets and (serial) devices.
 
* tests/socket.c: Tidied some compilation warnings.
 
* tests/testfs.c: Added umount stub function.
2000-06-12 Nick Garnett <nickg@cygnus.co.uk>
 
* include/sockio.h:
* include/fileio.h:
* src/fio.h:
* tests/testfs.c:
* src/socket.cxx:
* src/misc.cxx:
* src/file.cxx:
* src/fd.cxx:
* src/io.cxx:
* src/devfs.cxx:
Tidied up and sorted out locking protocols and synchronization
mechanisms.
 
2000-06-09 Nick Garnett <nickg@cygnus.co.uk>
 
* src/select.cxx:
* src/devfs.cxx:
* include/fileio.h:
* tests/testfs.c:
Added select() support.
 
* src/socket.cxx: Fixed a resource management bug in accept().
 
* tests/socket.c: Extended to test that all API calls work, at
least minimally, as they should. Still some calls to add here.
2000-06-07 Nick Garnett <nickg@cygnus.co.uk>
 
* tests/socket.c: Simple socket API test program. Needs much more
work to give full coverage.
 
* src/socket.cxx: Filled in some implementations. Changed some
type specifications.
 
* src/select.cxx: Added this file to contain select()
implementation. At present it does nothing.
 
* include/sockio.h:
Added definition of socklen_t for use when the NET package is
absent - just so this file compiles.
Added macro to generate an nstab entry.
Changed prototypes of socket operation ffunctions to better match
both API definition and BSD stack implementation.
 
* cdl/fileio.cdl: Added support for socket API. This is only
active if the NET package is present.
Added initial socket API test program.
 
2000-06-02 Nick Garnett <nickg@cygnus.co.uk>
 
* src/socket.cxx:
Added this file to implement socket interface. This is still a
rough draft that has not yet been tested.
 
* src/misc.cxx:
* src/io.cxx:
* src/fio.h: Various minor changes and bug fixes.
 
* src/file.cxx: Various bug fixes. Added pathconf().
 
* src/fd.cxx: Various changes and bug fixes, mostly in the
handling of the locking mechanisms.
 
* src/devfs.cxx: Added this filesystem to interface to the device
IO subsystem. Not yet tested.
 
* include/sockio.h: Various minor changes prompted by
implementation.
 
* include/fileio.h:
Added macros to instantiate filesystem and mount table entries.
Added mode mask for setting up f_flags.
Changed file object types, added device type.
 
* cdl/fileio.cdl:
Added some extra files to compile. Some now go in libextras.
Added table maxima for fstab, mtab and nstab.
Added tests.
 
* tests/fileio1.c: Added this simple test for the fileio
infrastructure.
 
* tests/testfs.c:
Created this simple ROM filesystem to test out the fileio
infrastructure. This is not really usable for anything other than
this, and should not be used in "production" systems. Hence its
presence in tests rather than src.
At present this only has support for open(), close(), read(),
write(), lseek() and unlink(). Other parts will be implemented as
and when required.
2000-05-31 Nick Garnett <nickg@cygnus.co.uk>
 
* src/fio.h:
* src/file.cxx:
* src/io.cxx:
* src/misc.cxx:
Roughed out most of the file IO infrastructure. While this code
compiles, none of it has actually been executed yet. A lot of this
was cut-and-paste-and-edit, so some minor blemishes are to be
expected.
 
* src/fd.cxx: Several modifications in response to implementing
rest of infrastructure. Added dup() and dup2() API routines.
 
* include/fileio.h: Many changes and tidies prompted by
infrastructure implementation.
 
* cdl/fileio.cdl: Added "implements" directives for isoinfra
interfaces. Extended compile to new files.
 
2000-05-26 Nick Garnett <nickg@cygnus.co.uk>
 
* include/fileio.h:
* include/sockio.h:
* src/fd.cxx:
* cdl/fileio.cdl:
Created these files as a start at defining the file IO package.
There is still a lot to do here, so expect radical changes to all
of these files in the near future.

powered by: WebSVN 2.1.0

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