⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unix_io.c

📁 busybox最新版的源码:学习和应用的好东东,多的不说了,大家看后再说吧
💻 C
📖 第 1 页 / 共 2 页
字号:
/* vi: set sw=4 ts=4: *//* * unix_io.c --- This is the Unix (well, really POSIX) implementation *	of the I/O manager. * * Implements a one-block write-through cache. * * Includes support for Windows NT support under Cygwin. * * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, *	2002 by Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU Public * License. * %End-Header% */#include <stdio.h>#include <string.h>#if HAVE_UNISTD_H#include <unistd.h>#endif#if HAVE_ERRNO_H#include <errno.h>#endif#include <fcntl.h>#include <time.h>#ifdef __linux__#include <sys/utsname.h>#endif#if HAVE_SYS_STAT_H#include <sys/stat.h>#endif#if HAVE_SYS_TYPES_H#include <sys/types.h>#endif#include <sys/resource.h>#include "ext2_fs.h"#include "ext2fs.h"/* * For checking structure magic numbers... */#define EXT2_CHECK_MAGIC(struct, code) \	  if ((struct)->magic != (code)) return (code)struct unix_cache {	char		*buf;	unsigned long	block;	int		access_time;	unsigned	dirty:1;	unsigned	in_use:1;};#define CACHE_SIZE 8#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */struct unix_private_data {	int	magic;	int	dev;	int	flags;	int	access_time;	ext2_loff_t offset;	struct unix_cache cache[CACHE_SIZE];};static errcode_t unix_open(const char *name, int flags, io_channel *channel);static errcode_t unix_close(io_channel channel);static errcode_t unix_set_blksize(io_channel channel, int blksize);static errcode_t unix_read_blk(io_channel channel, unsigned long block,			       int count, void *data);static errcode_t unix_write_blk(io_channel channel, unsigned long block,				int count, const void *data);static errcode_t unix_flush(io_channel channel);static errcode_t unix_write_byte(io_channel channel, unsigned long offset,				int size, const void *data);static errcode_t unix_set_option(io_channel channel, const char *option,				 const char *arg);static void reuse_cache(io_channel channel, struct unix_private_data *data,		 struct unix_cache *cache, unsigned long block);/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel * does not know buffered block devices - everything is raw. */#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)#define NEED_BOUNCE_BUFFER#else#undef NEED_BOUNCE_BUFFER#endifstatic struct struct_io_manager struct_unix_manager = {	EXT2_ET_MAGIC_IO_MANAGER,	"Unix I/O Manager",	unix_open,	unix_close,	unix_set_blksize,	unix_read_blk,	unix_write_blk,	unix_flush,#ifdef NEED_BOUNCE_BUFFER	0,#else	unix_write_byte,#endif	unix_set_option};io_manager unix_io_manager = &struct_unix_manager;/* * Here are the raw I/O functions */#ifndef NEED_BOUNCE_BUFFERstatic errcode_t raw_read_blk(io_channel channel,			      struct unix_private_data *data,			      unsigned long block,			      int count, void *buf){	errcode_t	retval;	ssize_t		size;	ext2_loff_t	location;	int		actual = 0;	size = (count < 0) ? -count : count * channel->block_size;	location = ((ext2_loff_t) block * channel->block_size) + data->offset;	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;		goto error_out;	}	actual = read(data->dev, buf, size);	if (actual != size) {		if (actual < 0)			actual = 0;		retval = EXT2_ET_SHORT_READ;		goto error_out;	}	return 0;error_out:	memset((char *) buf+actual, 0, size-actual);	if (channel->read_error)		retval = (channel->read_error)(channel, block, count, buf,					       size, actual, retval);	return retval;}#else /* NEED_BOUNCE_BUFFER *//* * Windows and FreeBSD block devices only allow sector alignment IO in offset and size */static errcode_t raw_read_blk(io_channel channel,			      struct unix_private_data *data,			      unsigned long block,			      int count, void *buf){	errcode_t	retval;	size_t		size, alignsize, fragment;	ext2_loff_t	location;	int		total = 0, actual;#define BLOCKALIGN 512	char		sector[BLOCKALIGN];	size = (count < 0) ? -count : count * channel->block_size;	location = ((ext2_loff_t) block * channel->block_size) + data->offset;#ifdef DEBUG	printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",			count, size, block, channel->block_size, location);#endif	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;		goto error_out;	}	fragment = size % BLOCKALIGN;	alignsize = size - fragment;	if (alignsize) {		actual = read(data->dev, buf, alignsize);		if (actual != alignsize)			goto short_read;	}	if (fragment) {		actual = read(data->dev, sector, BLOCKALIGN);		if (actual != BLOCKALIGN)			goto short_read;		memcpy(buf+alignsize, sector, fragment);	}	return 0;short_read:	if (actual>0)		total += actual;	retval = EXT2_ET_SHORT_READ;error_out:	memset((char *) buf+total, 0, size-actual);	if (channel->read_error)		retval = (channel->read_error)(channel, block, count, buf,					       size, actual, retval);	return retval;}#endifstatic errcode_t raw_write_blk(io_channel channel,			       struct unix_private_data *data,			       unsigned long block,			       int count, const void *buf){	ssize_t		size;	ext2_loff_t	location;	int		actual = 0;	errcode_t	retval;	if (count == 1)		size = channel->block_size;	else {		if (count < 0)			size = -count;		else			size = count * channel->block_size;	}	location = ((ext2_loff_t) block * channel->block_size) + data->offset;	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;		goto error_out;	}	actual = write(data->dev, buf, size);	if (actual != size) {		retval = EXT2_ET_SHORT_WRITE;		goto error_out;	}	return 0;error_out:	if (channel->write_error)		retval = (channel->write_error)(channel, block, count, buf,						size, actual, retval);	return retval;}/* * Here we implement the cache functions *//* Allocate the cache buffers */static errcode_t alloc_cache(io_channel channel,			     struct unix_private_data *data){	errcode_t		retval;	struct unix_cache	*cache;	int			i;	data->access_time = 0;	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {		cache->block = 0;		cache->access_time = 0;		cache->dirty = 0;		cache->in_use = 0;		if ((retval = ext2fs_get_mem(channel->block_size,					     &cache->buf)))			return retval;	}	return 0;}/* Free the cache buffers */static void free_cache(struct unix_private_data *data){	struct unix_cache	*cache;	int			i;	data->access_time = 0;	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {		cache->block = 0;		cache->access_time = 0;		cache->dirty = 0;		cache->in_use = 0;		ext2fs_free_mem(&cache->buf);		cache->buf = 0;	}}#ifndef NO_IO_CACHE/* * Try to find a block in the cache.  If the block is not found, and * eldest is a non-zero pointer, then fill in eldest with the cache * entry to that should be reused. */static struct unix_cache *find_cached_block(struct unix_private_data *data,					    unsigned long block,					    struct unix_cache **eldest){	struct unix_cache	*cache, *unused_cache, *oldest_cache;	int			i;	unused_cache = oldest_cache = 0;	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {		if (!cache->in_use) {			if (!unused_cache)				unused_cache = cache;			continue;		}		if (cache->block == block) {			cache->access_time = ++data->access_time;			return cache;		}		if (!oldest_cache ||		    (cache->access_time < oldest_cache->access_time))			oldest_cache = cache;	}	if (eldest)		*eldest = (unused_cache) ? unused_cache : oldest_cache;	return 0;}/* * Reuse a particular cache entry for another block. */static void reuse_cache(io_channel channel, struct unix_private_data *data,		 struct unix_cache *cache, unsigned long block){	if (cache->dirty && cache->in_use)		raw_write_blk(channel, data, cache->block, 1, cache->buf);	cache->in_use = 1;	cache->dirty = 0;	cache->block = block;	cache->access_time = ++data->access_time;}/* * Flush all of the blocks in the cache */static errcode_t flush_cached_blocks(io_channel channel,				     struct unix_private_data *data,				     int invalidate){	struct unix_cache	*cache;	errcode_t		retval, retval2;	int			i;	retval2 = 0;	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {		if (!cache->in_use)			continue;		if (invalidate)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -