/* * IMFS Directory Access Routines * * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id$ */ #if HAVE_CONFIG_H #include "config.h" #endif #include "imfs.h" #include #include /* * imfs_dir_open * * This rountine will verify that the node being opened as a directory is * in fact a directory node. If it is then the offset into the directory * will be set to 0 to position to the first directory entry. */ int imfs_dir_open( rtems_libio_t *iop, const char *pathname, int oflag, mode_t mode ) { IMFS_jnode_t *the_jnode; /* Is the node a directory ? */ the_jnode = (IMFS_jnode_t *) iop->pathinfo.node_access; if ( the_jnode->type != IMFS_DIRECTORY ) return -1; /* It wasn't a directory --> return error */ iop->offset = 0; return 0; } /* * imfs_dir_read * * This routine will read the next directory entry based on the directory * offset. The offset should be equal to -n- time the size of an individual * dirent structure. If n is not an integer multiple of the sizeof a * dirent structure, an integer division will be performed to determine * directory entry that will be returned in the buffer. Count should reflect * -m- times the sizeof dirent bytes to be placed in the buffer. * If there are not -m- dirent elements from the current directory position * to the end of the exisiting file, the remaining entries will be placed in * the buffer and the returned value will be equal to -m actual- times the * size of a directory entry. */ ssize_t imfs_dir_read( rtems_libio_t *iop, void *buffer, size_t count ) { /* * Read up to element iop->offset in the directory chain of the * imfs_jnode_t struct for this file descriptor. */ rtems_chain_node *the_node; rtems_chain_control *the_chain; IMFS_jnode_t *the_jnode; int bytes_transferred; int current_entry; int first_entry; int last_entry; struct dirent tmp_dirent; the_jnode = (IMFS_jnode_t *)iop->pathinfo.node_access; the_chain = &the_jnode->info.directory.Entries; if ( rtems_chain_is_empty( the_chain ) ) return 0; /* Move to the first of the desired directory entries */ the_node = rtems_chain_first( the_chain ); bytes_transferred = 0; first_entry = iop->offset; /* protect against using sizes that are not exact multiples of the */ /* -dirent- size. These could result in unexpected results */ last_entry = first_entry + (count/sizeof(struct dirent)) * sizeof(struct dirent); /* The directory was not empty so try to move to the desired entry in chain*/ for ( current_entry = 0; current_entry < last_entry; current_entry = current_entry + sizeof(struct dirent) ){ if ( rtems_chain_is_tail( the_chain, the_node ) ){ /* We hit the tail of the chain while trying to move to the first */ /* entry in the read */ return bytes_transferred; /* Indicate that there are no more */ /* entries to return */ } if( current_entry >= first_entry ) { /* Move the entry to the return buffer */ tmp_dirent.d_off = current_entry; tmp_dirent.d_reclen = sizeof( struct dirent ); the_jnode = (IMFS_jnode_t *) the_node; tmp_dirent.d_ino = the_jnode->st_ino; tmp_dirent.d_namlen = strlen( the_jnode->name ); strcpy( tmp_dirent.d_name, the_jnode->name ); memcpy( buffer + bytes_transferred, (void *)&tmp_dirent, sizeof( struct dirent ) ); iop->offset = iop->offset + sizeof(struct dirent); bytes_transferred = bytes_transferred + sizeof( struct dirent ); } the_node = the_node->next; } /* Success */ return bytes_transferred; } /* * imfs_dir_close * * This routine will be called by the generic close routine to cleanup any * resources that have been allocated for the management of the file */ int imfs_dir_close( rtems_libio_t *iop ) { /* * The generic close routine handles the deallocation of the file control * and associated memory. At present the imfs_dir_close simply * returns a successful completion status. */ return 0; } /* * imfs_dir_lseek * * This routine will behave in one of three ways based on the state of * argument whence. Based on the state of its value the offset argument will * be interpreted using one of the following methods: * * SEEK_SET - offset is the absolute byte offset from the start of the * logical start of the dirent sequence that represents the * directory * SEEK_CUR - offset is used as the relative byte offset from the current * directory position index held in the iop structure * SEEK_END - N/A --> This will cause an EINVAL to be returned. */ off_t imfs_dir_lseek( rtems_libio_t *iop, off_t offset, int whence ) { switch( whence ) { case SEEK_SET: /* absolute move from the start of the file */ case SEEK_CUR: /* relative move */ iop->offset = (iop->offset/sizeof(struct dirent)) * sizeof(struct dirent); break; case SEEK_END: /* Movement past the end of the directory via lseek */ /* is not a permitted operation */ default: rtems_set_errno_and_return_minus_one( EINVAL ); break; } return 0; }