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

📄 emd.c

📁 elinux jffs初始版本 具体了解JFFS的文件系统!
💻 C
字号:
/* *  linux/fs/umsdos/emd.c * *  Written 1993 by Jacques Gelinas * *  Extended MS-DOS directory handling functions */#include <linux/types.h>#include <linux/fcntl.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/msdos_fs.h>#include <linux/umsdos_fs.h>#include <asm/segment.h>#define PRINTK(x)#define Printk(x) printk x/*	Read a file into kernel space memory*/int umsdos_file_read_kmem(	struct inode *inode,	struct file *filp,	char *buf,	int count){	int ret;	int old_fs = get_fs();		set_fs (KERNEL_DS);	ret = fat_file_read(inode,filp,buf,count);	set_fs (old_fs);	return ret;}/*	Write to a file from kernel space*/int umsdos_file_write_kmem(	struct inode *inode,	struct file *filp,	const char *buf,	int count){	int ret;	int old_fs = get_fs();	set_fs (KERNEL_DS);	ret = fat_file_write(inode,filp,buf,count);	set_fs (old_fs);	return ret;}/*	Write a block of bytes into one EMD file.	The block of data is NOT in user space.	Return 0 if ok, a negative error code if not.*/int umsdos_emd_dir_write (	struct inode *emd_dir,	struct file *filp,	char *buf,	/* buffer in kernel memory, not in user space */	int count){	int written;	filp->f_flags = 0;	written = umsdos_file_write_kmem (emd_dir,filp,buf,count);	return written != count ? -EIO : 0;}/*	Read a block of bytes from one EMD file.	The block of data is NOT in user space.	Return 0 if ok, -EIO if any error.*/int umsdos_emd_dir_read (	struct inode *emd_dir,	struct file *filp,	char *buf,	/* buffer in kernel memory, not in user space */	int count){	int ret = 0;	int sizeread;	filp->f_flags = 0;	sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count);	if (sizeread != count){		printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n"			,filp->f_pos,sizeread,count);		ret = -EIO;	}	return ret;}/*	Locate the EMD file in a directory and optionally, creates it.	Return NULL if error. If ok, dir->u.umsdos_i.emd_inode */struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat){	struct inode *ret = NULL;	if (dir->u.umsdos_i.i_emd_dir != 0){		ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);		PRINTK (("deja trouve %d %x [%d] "			,dir->u.umsdos_i.i_emd_dir,ret,ret->i_count));	}else{		umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret);		PRINTK (("emd_dir_lookup "));		if (ret != NULL){			PRINTK (("Find --linux "));			dir->u.umsdos_i.i_emd_dir = ret->i_ino;		}else if (creat){			int code;			PRINTK (("avant create "));			dir->i_count++;			code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN				,S_IFREG|0777,&ret);			PRINTK (("Creat EMD code %d ret %x ",code,ret));			if (ret != NULL){				dir->u.umsdos_i.i_emd_dir = ret->i_ino;			}else{				printk ("UMSDOS: Can't create EMD file\n");			}		}	}	if (ret != NULL){		/* Disable UMSDOS_notify_change() for EMD file */		ret->u.umsdos_i.i_emd_owner = 0xffffffff;	}	return ret;}/*	Read an entry from the EMD file.	Support variable length record.	Return -EIO if error, 0 if ok.*/int umsdos_emd_dir_readentry (	struct inode *emd_dir,	struct file *filp,	struct umsdos_dirent *entry){	int ret = umsdos_emd_dir_read(emd_dir,filp,(char*)entry,UMSDOS_REC_SIZE);	if (ret == 0){		/* Variable size record. Maybe, we have to read some more */		int recsize = umsdos_evalrecsize (entry->name_len);		if (recsize > UMSDOS_REC_SIZE){			ret = umsdos_emd_dir_read(emd_dir,filp				,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE);					}	}	return ret;}/*	Write an entry in the EMD file.	Return 0 if ok, -EIO if some error.*/int umsdos_writeentry (	struct inode *dir,	struct inode *emd_dir,	struct umsdos_info *info,	int free_entry)		/* This entry is deleted, so Write all 0's */{	int ret = 0;	struct file filp;	struct umsdos_dirent *entry = &info->entry;	struct umsdos_dirent entry0;	if (free_entry){		/* #Specification: EMD file / empty entries			Unused entry in the EMD file are identify			by the name_len field equal to 0. However to			help future extension (or bug correction :-( ),			empty entries are filled with 0.		*/		memset (&entry0,0,sizeof(entry0));		entry = &entry0;	}else if (entry->name_len > 0){		memset (entry->name+entry->name_len,'\0'			,sizeof(entry->name)-entry->name_len);		/* #Specification: EMD file / spare bytes			10 bytes are unused in each record of the EMD. They			are set to 0 all the time. So it will be possible			to do new stuff and rely on the state of those			bytes in old EMD file around.		*/		memset (entry->spare,0,sizeof(entry->spare));	}	filp.f_pos = info->f_pos;	filp.f_reada = 0;	ret = umsdos_emd_dir_write(emd_dir,&filp,(char*)entry,info->recsize);	if (ret != 0){		printk ("UMSDOS: problem with EMD file. Can't write\n");	}else{		dir->i_ctime = dir->i_mtime = CURRENT_TIME;		dir->i_dirt = 1;	}	return ret;}#define CHUNK_SIZE (8*UMSDOS_REC_SIZE)struct find_buffer{	char buffer[CHUNK_SIZE];	int pos;	/* read offset in buffer */	int size;	/* Current size of buffer */	struct file filp;};/*	Fill the read buffer and take care of the byte remaining inside.	Unread bytes are simply move to the beginning.	Return -ENOENT if EOF, 0 if ok, a negative error code if any problem.*/static int umsdos_fillbuf (	struct inode *inode,	struct find_buffer *buf){	int ret = -ENOENT;	int mustmove = buf->size - buf->pos;	int mustread;	int remain;	if (mustmove > 0){		memcpy (buf->buffer,buf->buffer+buf->pos,mustmove);	}	buf->pos = 0;	mustread = CHUNK_SIZE - mustmove;	remain = inode->i_size - buf->filp.f_pos;	if (remain < mustread) mustread = remain;	if (mustread > 0){		ret = umsdos_emd_dir_read (inode,&buf->filp,buf->buffer+mustmove			,mustread);		if (ret == 0) buf->size = mustmove + mustread;			}else if (mustmove){		buf->size = mustmove;		ret = 0;	}	return ret;}/*	General search, locate a name in the EMD file or an empty slot to	store it. if info->entry.name_len == 0, search the first empty	slot (of the proper size).	Caller must do iput on *pt_emd_dir.	Return 0 if found, -ENOENT if not found, another error code if	other problem.	So this routine is used to either find an existing entry or to	create a new one, while making sure it is a new one. After you	get -ENOENT, you make sure the entry is stuffed correctly and	call umsdos_writeentry().	To delete an entry, you find it, zero out the entry (memset)	and call umsdos_writeentry().	All this to say that umsdos_writeentry must be call after this	function since it rely on the f_pos field of info.*/static int umsdos_find (	struct inode *dir,	struct umsdos_info *info,		/* Hold name and name_len */									/* Will hold the entry found */	struct inode **pt_emd_dir)		/* Will hold the emd_dir inode */									/* or NULL if not found */{	/* #Specification: EMD file structure		The EMD file uses a fairly simple layout. It is made of records		(UMSDOS_REC_SIZE == 64). When a name can't be written is a single		record, multiple contiguous record are allocated.	*/	int ret = -ENOENT;	struct inode *emd_dir = umsdos_emd_dir_lookup(dir,1);	if (emd_dir != NULL){		struct umsdos_dirent *entry = &info->entry;		int recsize = info->recsize;		struct {			off_t posok;	/* Position available to store the entry */			int found;		/* A valid empty position has been found */			off_t one;		/* One empty position -> maybe <- large enough */			int onesize;	/* size of empty region starting at one */		}empty;		/* Read several entries at a time to speed up the search */		struct find_buffer buf;		buf.pos = 0;		buf.size = 0;		buf.filp.f_pos = 0;		buf.filp.f_reada = 1;		empty.found = 0;		empty.posok = emd_dir->i_size;		empty.onesize = 0;		while (1){			struct umsdos_dirent *rentry = (struct umsdos_dirent*)				(buf.buffer + buf.pos);			int file_pos = buf.filp.f_pos - buf.size + buf.pos;			if (buf.pos == buf.size){				ret = umsdos_fillbuf (emd_dir,&buf);				if (ret < 0){					/* Not found, so note where it can be added */					info->f_pos = empty.posok;					break;				}			}else if (rentry->name_len == 0){				/* We are looking for an empty section at least */				/* recsize large */				if (entry->name_len == 0){					info->f_pos = file_pos;					ret = 0;					break;				}else if (!empty.found){					if (empty.onesize == 0){						/* This is the first empty record of a section */						empty.one = file_pos;					}					/* grow the empty section */					empty.onesize += UMSDOS_REC_SIZE;					if (empty.onesize == recsize){						/* here is a large enough section */						empty.posok = empty.one;						empty.found = 1;					}				}				buf.pos += UMSDOS_REC_SIZE;			}else{				int entry_size = umsdos_evalrecsize(rentry->name_len);				if (buf.pos+entry_size > buf.size){					ret = umsdos_fillbuf (emd_dir,&buf);					if (ret < 0){						/* Not found, so note where it can be added */						info->f_pos = empty.posok;						break;					}				}else{					empty.onesize = 0;	/* Reset the free slot search */					if (entry->name_len == rentry->name_len						&& memcmp(entry->name,rentry->name,rentry->name_len)							==0){						info->f_pos = file_pos;						*entry = *rentry;						ret = 0;						break;					}else{						buf.pos += entry_size;					}				}			}			}		umsdos_manglename(info);	}	*pt_emd_dir = emd_dir;	return ret;}/*	Add a new entry in the emd file	Return 0 if ok or a negative error code.	Return -EEXIST if the entry already exist.	Complete the information missing in info.*/int umsdos_newentry (	struct inode *dir,	struct umsdos_info *info){	struct inode *emd_dir;	int ret = umsdos_find (dir,info,&emd_dir);	if (ret == 0){		ret = -EEXIST;	}else if (ret == -ENOENT){		ret = umsdos_writeentry(dir,emd_dir,info,0);		PRINTK (("umsdos_newentry EDM ret = %d\n",ret));	}	iput (emd_dir);	return ret;}/*	Create a new hidden link.	Return 0 if ok, an error code if not.*/int umsdos_newhidden (	struct inode *dir,	struct umsdos_info *info){	struct inode *emd_dir;	int ret;	umsdos_parse ("..LINK",6,info);	info->entry.name_len = 0;	ret = umsdos_find (dir,info,&emd_dir);	iput (emd_dir);	if (ret == -ENOENT || ret == 0){		/* #Specification: hard link / hidden name			When a hard link is created, the original file is renamed			to a hidden name. The name is "..LINKNNN" where NNN is a			number define from the entry offset in the EMD file.		*/		info->entry.name_len = sprintf (info->entry.name,"..LINK%ld"			,info->f_pos);		ret = 0;	}	return ret;}/*	Remove an entry from the emd file	Return 0 if ok, a negative error code otherwise.	Complete the information missing in info.*/int umsdos_delentry (	struct inode *dir,	struct umsdos_info *info,	int isdir){	struct inode *emd_dir;	int ret = umsdos_find (dir,info,&emd_dir);	if (ret == 0){		if (info->entry.name_len != 0){			if ((isdir != 0) != (S_ISDIR(info->entry.mode) != 0)){				if (S_ISDIR(info->entry.mode)){					ret = -EISDIR;				}else{					ret = -ENOTDIR;				}			}else{				ret = umsdos_writeentry(dir,emd_dir,info,1);			}		}	}	iput(emd_dir);	return ret;}/*	Verify is a EMD directory is empty.	Return 0 if not empty		   1 if empty		   2 if empty, no EMD file.*/int umsdos_isempty (struct inode *dir){	int ret = 2;	struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);	/* If the EMD file does not exist, it is certainly empty :-) */	if (emd_dir != NULL){		struct file filp;		/* Find an empty slot */		filp.f_pos = 0;		filp.f_reada = 1;		filp.f_flags = O_RDONLY;		ret = 1;		while (filp.f_pos < emd_dir->i_size){			struct umsdos_dirent entry;			if (umsdos_emd_dir_readentry(emd_dir,&filp,&entry)!=0){				ret = 0;				break;			}else if (entry.name_len != 0){				ret = 0;				break;			}			}		iput (emd_dir);	}	return ret;}/*	Locate an entry in a EMD directory.	Return 0 if ok, errcod if not, generally -ENOENT.*/int umsdos_findentry (	struct inode *dir,	struct umsdos_info *info,	int expect)		/* 0: anything */					/* 1: file */					/* 2: directory */{	struct inode *emd_dir;	int ret = umsdos_find (dir,info,&emd_dir);	if (ret == 0){		if (expect != 0){			if (S_ISDIR(info->entry.mode)){				if (expect != 2) ret = -EISDIR;			}else if (expect == 2){				ret = -ENOTDIR;			}		}	}	iput (emd_dir);	return ret;}

⌨️ 快捷键说明

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