dir.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 660 行 · 第 1/2 页

C
660
字号
/* *  linux/fs/fat/dir.c * *  directory handling functions for fat-based filesystems * *  Written 1992,1993 by Werner Almesberger * *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu> * *  VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu> *  Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk> *  Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV */#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))#include <linux/version.h>#include <linux/fs.h>#include <linux/msdos_fs.h>#include <linux/nls.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/string.h>#include <linux/ioctl.h>#include <linux/dirent.h>#include <linux/mm.h>#include <linux/ctype.h>#include <asm/uaccess.h>#include "msbuffer.h"#define PRINTK(X)static ssize_t fat_dir_read(struct file * filp, char * buf,			    size_t count, loff_t *ppos){	return -EISDIR;}struct file_operations fat_dir_operations = {	NULL,			/* lseek - default */	fat_dir_read,		/* read */	NULL,			/* write - bad */	fat_readdir,		/* readdir */	NULL,			/* select v2.0.x/poll v2.1.x - default */	fat_dir_ioctl,		/* ioctl - default */	NULL,			/* mmap */	NULL,			/* no special open code */	NULL,			/* flush */	NULL,			/* no special release code */	file_fsync		/* fsync */};/* * Convert Unicode 16 to UTF8, translated Unicode, or ASCII. * If uni_xlate is enabled and we * can't get a 1:1 conversion, use a colon as an escape character since * it is normally invalid on the vfat filesystem.  The following three * characters are a sort of uuencoded 16 bit Unicode value.  This lets * us do a full dump and restore of Unicode filenames.  We could get * into some trouble with long Unicode names, but ignore that right now. * Ahem... Stack smashing in ring 0 isn't fun. Fixed. */static intuni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,	    struct nls_table *nls){	unsigned char *ip, *op;	unsigned char ch, cl;	unsigned char *uni_page;	unsigned short val;	ip = uni;	op = ascii;	while (*ip || ip[1]) {		cl = *ip++;		ch = *ip++;		uni_page = nls->page_uni2charset[ch];		if (uni_page && uni_page[cl]) {			*op++ = uni_page[cl];		} else {			if (uni_xlate == 1) {				*op++ = ':';				val = (cl << 8) + ch;				op[2] = fat_uni2esc[val & 0x3f];				val >>= 6;				op[1] = fat_uni2esc[val & 0x3f];				val >>= 6;				*op = fat_uni2esc[val & 0x3f];				op += 3;			} else {				*op++ = '?';			}		}		/* We have some slack there, so it's OK */		if (op>ascii+256) {			op = ascii + 256;			break;		}	}	*op = 0;	return (op - ascii);}#if 0static void dump_de(struct msdos_dir_entry *de){	int i;	unsigned char *p = (unsigned char *) de;	printk("[");	for (i = 0; i < 32; i++, p++) {		printk("%02x ", *p);	}	printk("]\n");}#endifstatic int memicmp(const char *s1, const char *s2, int len) {	while(len--) if (tolower(*s1++)!=tolower(*s2++)) return 1;	return 0;}/* * Return values: negative -> error, 0 -> not found, positive -> found, * value is the total amount of slots, including the shortname entry. */int fat_search_long(	struct inode *inode, const char *name, int name_len, int anycase,	loff_t *spos, loff_t *lpos){	struct super_block *sb = inode->i_sb;	int ino,i,i2,last;	char c;	struct buffer_head *bh = NULL;	struct msdos_dir_entry *de;	loff_t cpos = MSDOS_I(inode)->i_last_pos;	loff_t barrier = 0;	char bufname[14];	unsigned char long_slots;	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;	int utf8 = MSDOS_SB(sb)->options.utf8;	unsigned char *unicode = NULL;	struct nls_table *nls = MSDOS_SB(sb)->nls_io;	int res = 0;	while(1) {		if (barrier && cpos>=barrier)			goto EODir;rescan:		if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)			goto EODir;parse_record:		long_slots = 0;		if (de->name[0] == (__s8) DELETED_FLAG)			continue;		if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))			continue;		if (de->attr != ATTR_EXT && IS_FREE(de->name))			continue;		if (de->attr ==  ATTR_EXT) {			struct msdos_dir_slot *ds;			int offset;			unsigned char id;			unsigned char slot;			unsigned char slots;			unsigned char sum;			unsigned char alias_checksum;			if (!unicode) {				unicode = (unsigned char *)					__get_free_page(GFP_KERNEL);				if (!unicode) {					fat_brelse(sb, bh);					return -ENOMEM;				}			}parse_long:			slots = 0;			offset = 0;			ds = (struct msdos_dir_slot *) de;			id = ds->id;			if (!(id & 0x40))				continue;			slots = id & ~0x40;			if (slots > 20 || !slots)	/* ceil(256 * 2 / 26) */				continue;			long_slots = slots;			alias_checksum = ds->alias_checksum;			slot = slots;			while (1) {				slot--;				offset = slot * 26;				memcpy(&unicode[offset], ds->name0_4, 10);				memcpy(&unicode[offset+10], ds->name5_10, 12);				memcpy(&unicode[offset+22], ds->name11_12, 4);				offset += 26;				if (ds->id & 0x40) {					unicode[offset] = 0;					unicode[offset+1] = 0;				}				if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)					goto EODir;				if (slot == 0)					break;				ds = (struct msdos_dir_slot *) de;				if (ds->attr !=  ATTR_EXT)					goto parse_record;				if ((ds->id & ~0x40) != slot)					goto parse_long;				if (ds->alias_checksum != alias_checksum)					goto parse_long;			}			if (de->name[0] == (__s8) DELETED_FLAG)				continue;			if (de->attr ==  ATTR_EXT)				goto parse_long;			if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))				continue;			for (sum = 0, i = 0; i < 11; i++)				sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];			if (sum != alias_checksum)				long_slots = 0;		}		for (i = 0, last = 0; i < 8;) {			if (!(c = de->name[i])) break;			if (c >= 'A' && c <= 'Z') c += 32;			if (c == 0x05) c = 0xE5;			if ((bufname[i++] = c) != ' ')				last = i;		}		i = last;		bufname[i++] = '.';		for (i2 = 0; i2 < 3; i2++) {			if (!(c = de->ext[i2])) break;			if (c >= 'A' && c <= 'Z') c += 32;			if ((bufname[i++] = c) != ' ')				last = i;		}		if (!last)			continue;		if (last==name_len)			if ((!anycase && !memcmp(name, bufname, last)) ||			    (anycase && !memicmp(name, bufname, last)))			goto Found;		if (long_slots) {			char longname[260];	/* 256 + 4 */			unsigned char long_len;			long_len = utf8				?utf8_wcstombs(longname, (__u16 *) unicode, 260)				:uni16_to_x8(longname, unicode, uni_xlate, nls);			if (long_len != name_len)				continue;			if ((!anycase && !memcmp(name, longname, long_len)) ||			    (anycase && !memicmp(name, longname, long_len)))				goto Found;		}	}Found:	fat_brelse(sb, bh);	res = long_slots + 1;	*spos = cpos - sizeof(struct msdos_dir_entry);	*lpos = cpos - res*sizeof(struct msdos_dir_entry);	MSDOS_I(inode)->i_last_pos = cpos;exit:	if (unicode) {		free_page((unsigned long) unicode);	}	return res;EODir:	if (!MSDOS_I(inode)->i_last_pos)		goto exit;	if (barrier) {		MSDOS_I(inode)->i_last_pos = 0;		goto exit;	}	barrier = MSDOS_I(inode)->i_last_pos;	cpos = 0;	goto rescan;}static int fat_readdirx(	struct inode *inode,	struct file *filp,	void *dirent,	filldir_t filldir,	int shortnames,	int both){	struct super_block *sb = inode->i_sb;	int ino,inum,i,i2,last;	char c;	struct buffer_head *bh;	struct msdos_dir_entry *de;	unsigned long lpos;	loff_t cpos;	unsigned char long_slots;	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;	int utf8 = MSDOS_SB(sb)->options.utf8;	unsigned char *unicode = NULL;	struct nls_table *nls = MSDOS_SB(sb)->nls_io;	char bufname[14];	char *ptname = bufname;	int dotoffset = 0;	unsigned long *furrfu = &lpos;	unsigned long dummy;	cpos = filp->f_pos;/* Fake . and .. for the root directory. */	if (inode->i_ino == MSDOS_ROOT_INO) {		while (cpos < 2) {			if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO) < 0)				return 0;			cpos++;			filp->f_pos++;		}		if (cpos == 2) {			dummy = 2;			furrfu = &dummy;			cpos = 0;		}	}

⌨️ 快捷键说明

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