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 |
"romfs", "msdos", "ext2" 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 "/") to the correct filesystem. When a file |
name that begins with "/" 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 "/", 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 "/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. |
</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 ".." entries. |
</para> |
|
<para> |
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. |
</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 "/dev", 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, "devfs", that is |
mounted on "/dev". 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. |