📄 memfile.c
字号:
/* * IMFS Device Node Handlers * * This file contains the set of handlers used to process operations on * IMFS memory file nodes. The memory files are created in memory using * malloc'ed memory. Thus any data stored in one of these files is lost * at system shutdown unless special arrangements to copy the data to * some type of non-volailte storage are made by the application. * * 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: memfile.c,v 1.19.2.1 2003/09/04 18:47:02 joel Exp $ */#if HAVE_CONFIG_H#include "config.h"#endif#include <stdlib.h>#include <string.h>#include <assert.h>#include <errno.h>#include <rtems.h>#include <rtems/libio.h>#include "imfs.h"#include <rtems/libio_.h>#include <rtems/seterr.h>#define MEMFILE_STATIC /* * Prototypes of private routines */MEMFILE_STATIC int IMFS_memfile_extend( IMFS_jnode_t *the_jnode, off_t new_length);MEMFILE_STATIC int IMFS_memfile_addblock( IMFS_jnode_t *the_jnode, unsigned int block);MEMFILE_STATIC int IMFS_memfile_remove_block( IMFS_jnode_t *the_jnode, unsigned int block);MEMFILE_STATIC block_p *IMFS_memfile_get_block_pointer( IMFS_jnode_t *the_jnode, unsigned int block, int malloc_it);MEMFILE_STATIC ssize_t IMFS_memfile_read( IMFS_jnode_t *the_jnode, off_t start, unsigned char *destination, unsigned int length);ssize_t IMFS_memfile_write( /* cannot be static as used in imfs_fchmod.c */ IMFS_jnode_t *the_jnode, off_t start, const unsigned char *source, unsigned int length);int memfile_check_rmnod( IMFS_jnode_t *the_jnode );void *memfile_alloc_block(void);void memfile_free_block( void *memory);/* * memfile_open * * This routine processes the open() system call. Note that there is * nothing special to be done at open() time. */int memfile_open( rtems_libio_t *iop, const char *pathname, unsigned32 flag, unsigned32 mode){ IMFS_jnode_t *the_jnode; the_jnode = iop->file_info; if (iop->flags & LIBIO_FLAGS_APPEND) iop->offset = the_jnode->info.file.size; iop->size = the_jnode->info.file.size; return 0;}/* * memfile_close * * This routine processes the close() system call. Note that there is * nothing to flush or memory to free at this point. */int memfile_close( rtems_libio_t *iop){ IMFS_jnode_t *the_jnode; the_jnode = iop->file_info; if (iop->flags & LIBIO_FLAGS_APPEND) iop->offset = the_jnode->info.file.size; memfile_check_rmnod( the_jnode ); return 0;}/* * memfile_read * * This routine processes the read() system call. */ssize_t memfile_read( rtems_libio_t *iop, void *buffer, unsigned32 count){ IMFS_jnode_t *the_jnode; the_jnode = iop->file_info; return IMFS_memfile_read( the_jnode, iop->offset, buffer, count );}/* * memfile_write * * This routine processes the write() system call. */ssize_t memfile_write( rtems_libio_t *iop, const void *buffer, unsigned32 count){ IMFS_jnode_t *the_jnode; ssize_t status; the_jnode = iop->file_info; status = IMFS_memfile_write( the_jnode, iop->offset, buffer, count ); iop->size = the_jnode->info.file.size; return status;}/* * memfile_ioctl * * This routine processes the ioctl() system call. * * NOTE: No ioctl()'s are supported for in-memory files. */int memfile_ioctl( rtems_libio_t *iop, unsigned32 command, void *buffer){ IMFS_jnode_t *the_jnode; the_jnode = iop->file_info; return 0;}/* * memfile_lseek * * This routine processes the lseek() system call. */int memfile_lseek( rtems_libio_t *iop, off_t offset, int whence){ IMFS_jnode_t *the_jnode; the_jnode = iop->file_info; if (the_jnode->type == IMFS_LINEAR_FILE) { if (iop->offset > the_jnode->info.linearfile.size) iop->offset = the_jnode->info.linearfile.size; } else { /* Must be a block file (IMFS_MEMORY_FILE). */ if (IMFS_memfile_extend( the_jnode, iop->offset )) rtems_set_errno_and_return_minus_one( ENOSPC ); iop->size = the_jnode->info.file.size; } return iop->offset;}/* * memfile_stat * * This IMFS_stat() can be used. *//* * memfile_ftruncate * * This routine processes the ftruncate() system call. */int memfile_ftruncate( rtems_libio_t *iop, off_t length){ IMFS_jnode_t *the_jnode; the_jnode = iop->file_info; /* * POSIX 1003.1b does not specify what happens if you truncate a file * and the new length is greater than the current size. We treat this * as an extend operation. */ if ( length > the_jnode->info.file.size ) return IMFS_memfile_extend( the_jnode, length ); /* * The in-memory files do not currently reclaim memory until the file is * deleted. So we leave the previously allocated blocks in place for * future use and just set the length. */ the_jnode->info.file.size = length; iop->size = the_jnode->info.file.size; IMFS_update_atime( the_jnode ); return 0;}/* * IMFS_memfile_extend * * This routine insures that the in-memory file is of the length * specified. If necessary, it will allocate memory blocks to * extend the file. */MEMFILE_STATIC int IMFS_memfile_extend( IMFS_jnode_t *the_jnode, off_t new_length){ unsigned int block; unsigned int new_blocks; unsigned int old_blocks; /* * Perform internal consistency checks */ assert( the_jnode ); if ( !the_jnode ) rtems_set_errno_and_return_minus_one( EIO ); assert( the_jnode->type == IMFS_MEMORY_FILE ); if ( the_jnode->type != IMFS_MEMORY_FILE ) rtems_set_errno_and_return_minus_one( EIO ); if ( new_length >= IMFS_MEMFILE_MAXIMUM_SIZE ) rtems_set_errno_and_return_minus_one( EINVAL ); if ( new_length <= the_jnode->info.file.size ) return 0; /* * Calculate the number of range of blocks to allocate */ new_blocks = new_length / IMFS_MEMFILE_BYTES_PER_BLOCK; old_blocks = the_jnode->info.file.size / IMFS_MEMFILE_BYTES_PER_BLOCK; /* * Now allocate each of those blocks. */ for ( block=old_blocks ; block<=new_blocks ; block++ ) { if ( IMFS_memfile_addblock( the_jnode, block ) ) { for ( ; block>=old_blocks ; block-- ) { IMFS_memfile_remove_block( the_jnode, block ); } rtems_set_errno_and_return_minus_one( ENOSPC ); } } /* * Set the new length of the file. */ the_jnode->info.file.size = new_length; return 0;}/* * IMFS_memfile_addblock * * This routine adds a single block to the specified in-memory file. */MEMFILE_STATIC int IMFS_memfile_addblock( IMFS_jnode_t *the_jnode, unsigned int block){ block_p memory; block_p *block_entry_ptr; assert( the_jnode ); if ( !the_jnode ) rtems_set_errno_and_return_minus_one( EIO ); assert( the_jnode->type == IMFS_MEMORY_FILE ); if ( the_jnode->type != IMFS_MEMORY_FILE ) rtems_set_errno_and_return_minus_one( EIO ); block_entry_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 1 ); if ( *block_entry_ptr ) return 0;#if 0 printf( "%d %p", block, block_entry_ptr ); fflush(stdout);#endif memory = memfile_alloc_block(); if ( !memory ) return 1; *block_entry_ptr = memory; return 0;}/* * IMFS_memfile_remove_block * * This routine removes the specified block from the in-memory file. * * NOTE: This is a support routine and is called only to remove * the last block or set of blocks in a file. Removing a * block from the middle of a file would be exceptionally * dangerous and the results unpredictable. */MEMFILE_STATIC int IMFS_memfile_remove_block( IMFS_jnode_t *the_jnode, unsigned int block){ block_p *block_entry_ptr; block_p ptr; block_entry_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 ); ptr = *block_entry_ptr; *block_entry_ptr = 0; memfile_free_block( ptr ); return 1;}/* * memfile_free_blocks_in_table * * This is a support routine for IMFS_memfile_remove. It frees all the * blocks in one of the indirection tables. */void memfile_free_blocks_in_table( block_p **block_table, int entries){ int i; block_p *b; /* * Perform internal consistency checks */ assert( block_table ); if ( !block_table ) return; /* * Now go through all the slots in the table and free the memory. */ b = *block_table; for ( i=0 ; i<entries ; i++ ) { if ( b[i] ) { memfile_free_block( b[i] ); b[i] = 0; } } /* * Now that all the blocks in the block table are free, we can * free the block table itself. */ memfile_free_block( *block_table ); *block_table = 0;}/* * IMFS_memfile_remove * * This routine frees all memory associated with an in memory file. * * NOTE: This is an exceptionally conservative implementation. * It will check EVERY pointer which is non-NULL and insure * any child non-NULL pointers are freed. Optimistically, all that * is necessary is to scan until a NULL pointer is found. There * should be no allocated data past that point. * * In experimentation on the powerpc simulator, it was noted * that using blocks which held 128 slots versus 16 slots made * a significant difference in the performance of this routine. * * Regardless until the IMFS implementation is proven, it * is better to stick to simple, easy to understand algorithms. */int IMFS_memfile_remove( IMFS_jnode_t *the_jnode){ IMFS_memfile_t *info; int i; int j; unsigned int to_free; block_p *p; /* * Perform internal consistency checks */ assert( the_jnode ); if ( !the_jnode ) rtems_set_errno_and_return_minus_one( EIO ); assert( the_jnode->type == IMFS_MEMORY_FILE ); if ( the_jnode->type != IMFS_MEMORY_FILE ) rtems_set_errno_and_return_minus_one( EIO ); /* * Eventually this could be set smarter at each call to * memfile_free_blocks_in_table to greatly speed this up. */ to_free = IMFS_MEMFILE_BLOCK_SLOTS; /* * Now start freeing blocks in this order: * + indirect * + doubly indirect * + triply indirect */ info = &the_jnode->info.file; if ( info->indirect ) { memfile_free_blocks_in_table( &info->indirect, to_free ); } if ( info->doubly_indirect ) { for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) { if ( info->doubly_indirect[i] ) { memfile_free_blocks_in_table( (block_p **)&info->doubly_indirect[i], to_free ); } } memfile_free_blocks_in_table( &info->doubly_indirect, to_free ); } if ( info->triply_indirect ) { for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) { p = (block_p *) info->triply_indirect[i]; if ( !p ) /* ensure we have a valid pointer */ break; for ( j=0 ; j<IMFS_MEMFILE_BLOCK_SLOTS ; j++ ) { if ( p[j] ) { memfile_free_blocks_in_table( (block_p **)&p[j], to_free); } } memfile_free_blocks_in_table( (block_p **)&info->triply_indirect[i], to_free ); } memfile_free_blocks_in_table( (block_p **)&info->triply_indirect, to_free ); } return 0;}/* * IMFS_memfile_read * * This routine read from memory file pointed to by the_jnode into * the specified data buffer specified by destination. The file * is NOT extended. An offset greater than the length of the file * is considered an error. Read from an offset for more bytes than * are between the offset and the end of the file will result in * reading the data between offset and the end of the file (truncated * read). */MEMFILE_STATIC ssize_t IMFS_memfile_read( IMFS_jnode_t *the_jnode, off_t start, unsigned char *destination, unsigned int length){ block_p *block_ptr; unsigned int block; unsigned int my_length; unsigned int to_copy = 0; unsigned int last_byte; unsigned int copied; unsigned int start_offset; unsigned char *dest; dest = destination; /* * Perform internal consistency checks */ assert( the_jnode ); if ( !the_jnode ) rtems_set_errno_and_return_minus_one( EIO ); assert( the_jnode->type == IMFS_MEMORY_FILE ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -