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

📄 dir.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/umsdos/dir.c * *  Written 1993 by Jacques Gelinas *      Inspired from linux/fs/msdos/... : Werner Almesberger * *  Extended MS-DOS directory handling functions */#include <linux/sched.h>#include <linux/string.h>#include <linux/fs.h>#include <linux/msdos_fs.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/limits.h>#include <linux/umsdos_fs.h>#include <linux/slab.h>#include <linux/pagemap.h>#define UMSDOS_SPECIAL_DIRFPOS	3extern struct dentry *saved_root;extern struct inode *pseudo_root;/* #define UMSDOS_DEBUG_VERBOSE 1 *//* * Dentry operations routines *//* nothing for now ... */static int umsdos_dentry_validate(struct dentry *dentry, int flags){	return 1;}/* for now, drop everything to force lookups ... *//* ITYM s/everything/& positive/... */static int umsdos_dentry_dput(struct dentry *dentry){	struct inode *inode = dentry->d_inode;	if (inode) {		return 1;	}	return 0;}struct dentry_operations umsdos_dentry_operations ={	d_revalidate:	umsdos_dentry_validate,	d_delete:	umsdos_dentry_dput,};struct UMSDOS_DIR_ONCE {	void *dirbuf;	filldir_t filldir;	int count;	int stop;};/* * Record a single entry the first call. * Return -EINVAL the next one. * NOTE: filldir DOES NOT use a dentry */static int umsdos_dir_once (	void *buf,				const char *name,				int len,				loff_t offset,				ino_t ino,				unsigned type){	int ret = -EINVAL;	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;	if (d->count == 0) {		PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", 			len, name, offset));		ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN);		d->stop = ret < 0;		d->count = 1;	}	return ret;}/* * Read count directory entries from directory filp * Return a negative value from linux/errno.h. * Return > 0 if success (the number of bytes written by filldir). *  * This function is used by the normal readdir VFS entry point, * and in order to get the directory entry from a file's dentry. * See umsdos_dentry_to_entry() below. */ static int umsdos_readdir_x (struct inode *dir, struct file *filp,				void *dirbuf, struct umsdos_dirent *u_entry,				filldir_t filldir){	struct dentry *demd;	off_t start_fpos;	int ret = 0;	loff_t pos;	umsdos_startlookup (dir);	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root) {		/*		 * We don't need to simulate this pseudo directory		 * when umsdos_readdir_x is called for internal operation		 * of umsdos. This is why dirent_in_fs is tested		 */		/* #Specification: pseudo root / directory /DOS		 * When umsdos operates in pseudo root mode (C:\linux is the		 * linux root), it simulate a directory /DOS which points to		 * the real root of the file system.		 */		Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n"));		if (filldir (dirbuf, "DOS", 3, 				UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) {			filp->f_pos++;		}		goto out_end;	}	if (filp->f_pos < 2 || 	    (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {			int last_f_pos = filp->f_pos;		struct UMSDOS_DIR_ONCE bufk;		Printk (("umsdos_readdir_x: . or .. /mn/?\n"));		bufk.dirbuf = dirbuf;		bufk.filldir = filldir;		bufk.count = 0;		ret = fat_readdir (filp, &bufk, umsdos_dir_once);		if (last_f_pos > 0 && filp->f_pos > last_f_pos)			filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;		if (u_entry != NULL)			u_entry->flags = 0;		goto out_end;	}	Printk (("umsdos_readdir_x: normal file /mn/?\n"));	/* get the EMD dentry */	demd = umsdos_get_emd_dentry(filp->f_dentry);	ret = PTR_ERR(demd);	if (IS_ERR(demd))		goto out_end;	ret = -EIO;	if (!demd->d_inode) {		printk(KERN_WARNING 			"umsdos_readir_x: EMD file %s/%s not found\n",			demd->d_parent->d_name.name, demd->d_name.name);		goto out_dput;	}	pos = filp->f_pos;	start_fpos = filp->f_pos;	if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1)		pos = 0;	ret = 0;	while (pos < demd->d_inode->i_size) {		off_t cur_f_pos = pos;		struct dentry *dret;		struct inode *inode;		struct umsdos_dirent entry;		struct umsdos_info info;		ret = -EIO;		if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0)			break;		if (entry.name_len == 0)			continue;#ifdef UMSDOS_DEBUG_VERBOSEif (entry.flags & UMSDOS_HLINK)printk("umsdos_readdir_x: %s/%s is hardlink\n",filp->f_dentry->d_name.name, entry.name);#endif		umsdos_parse (entry.name, entry.name_len, &info);		info.f_pos = cur_f_pos;		umsdos_manglename (&info);		/*		 * Do a real lookup on the short name.		 */		dret = umsdos_covered(filp->f_dentry, info.fake.fname,						 info.fake.len);		ret = PTR_ERR(dret);		if (IS_ERR(dret))			break;		/*		 * If the file wasn't found, remove it from the EMD.		 */		inode = dret->d_inode;		if (!inode)			goto remove_name;#ifdef UMSDOS_DEBUG_VERBOSEif (inode->u.umsdos_i.i_is_hlink)printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n",dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino);#endifPrintk (("Found %s/%s, ino=%ld, flags=%x\n",dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino,entry.flags));		/* check whether to resolve a hard-link */		if ((entry.flags & UMSDOS_HLINK) &&		    !inode->u.umsdos_i.i_is_hlink) {			dret = umsdos_solve_hlink (dret);			ret = PTR_ERR(dret);			if (IS_ERR(dret))				break;			inode = dret->d_inode;			if (!inode) {printk("umsdos_readdir_x: %s/%s negative after link\n",dret->d_parent->d_name.name, dret->d_name.name);				goto clean_up;			}		}		/* #Specification:  pseudo root / reading real root		 * The pseudo root (/linux) is logically		 * erased from the real root.  This means that		 * ls /DOS, won't show "linux". This avoids		 * infinite recursion (/DOS/linux/DOS/linux/...) while		 * walking the file system.		 */		if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) {			if (filldir (dirbuf, entry.name, entry.name_len,				 cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) {				pos = cur_f_pos;			}Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n",dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino));			if (u_entry != NULL)				*u_entry = entry;			dput(dret);			ret = 0;			break;		}	clean_up:		dput(dret);		continue;	remove_name:		/* #Specification:  umsdos / readdir / not in MSDOS		 * During a readdir operation, if the file is not		 * in the MS-DOS directory any more, the entry is		 * removed from the EMD file silently.		 */#ifdef UMSDOS_PARANOIAprintk("umsdos_readdir_x: %s/%s out of sync, erasing\n",filp->f_dentry->d_name.name, info.entry.name);#endif		ret = umsdos_delentry(filp->f_dentry, &info, 					S_ISDIR(info.entry.mode));		if (ret)			printk(KERN_WARNING 				"umsdos_readdir_x: delentry %s, err=%d\n",				info.entry.name, ret);		goto clean_up;	}	/*	 * If the fillbuf has failed, f_pos is back to 0.	 * To avoid getting back into the . and .. state	 * (see comments at the beginning), we put back	 * the special offset.	 */	filp->f_pos = pos;	if (filp->f_pos == 0)		filp->f_pos = start_fpos;out_dput:	dput(demd);out_end:	umsdos_endlookup (dir);		Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n",		dir, filp->f_pos, ret));	return ret;}/* * Read count directory entries from directory filp. * Return a negative value from linux/errno.h. * Return 0 or positive if successful. */ static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir){	struct inode *dir = filp->f_dentry->d_inode;	int ret = 0, count = 0;	struct UMSDOS_DIR_ONCE bufk;	bufk.dirbuf = dirbuf;	bufk.filldir = filldir;	bufk.stop = 0;	Printk (("UMSDOS_readdir in\n"));	while (ret == 0 && bufk.stop == 0) {		struct umsdos_dirent entry;		bufk.count = 0;		ret = umsdos_readdir_x (dir, filp, &bufk, &entry, 					umsdos_dir_once);		if (bufk.count == 0)			break;		count += bufk.count;	}	Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", 		ret, count, filp->f_pos));	return count ? : ret;}/* * Complete the inode content with info from the EMD file. * * This function modifies the state of a dir inode.  It decides * whether the dir is a UMSDOS or DOS directory.  This is done * deeper in umsdos_patch_inode() called at the end of this function. *  * Because it is does disk access, umsdos_patch_inode() may block. * At the same time, another process may get here to initialise * the same directory inode. There are three cases. *  * 1) The inode is already initialised.  We do nothing. * 2) The inode is not initialised.  We lock access and do it. * 3) Like 2 but another process has locked the inode, so we try * to lock it and check right afterward check whether * initialisation is still needed. *  *  * Thanks to the "mem" option of the kernel command line, it was * possible to consistently reproduce this problem by limiting * my memory to 4 MB and running X. * * Do this only if the inode is freshly read, because we will lose * the current (updated) content. * * A lookup of a mount point directory yield the inode into * the other fs, so we don't care about initialising it. iget() * does this automatically. */void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info){	struct inode *inode = dentry->d_inode;	struct umsdos_dirent *entry = &info->entry;	/*	 * This part of the initialization depends only on i_patched.	 */	if (inode->u.umsdos_i.i_patched)		goto out;	inode->u.umsdos_i.i_patched = 1;	if (S_ISREG (entry->mode))		entry->mtime = inode->i_mtime;	inode->i_mode = entry->mode;	inode->i_rdev = to_kdev_t (entry->rdev);	inode->i_atime = entry->atime;	inode->i_ctime = entry->ctime;	inode->i_mtime = entry->mtime;	inode->i_uid = entry->uid;	inode->i_gid = entry->gid;	/* #Specification: umsdos / i_nlink	 * The nlink field of an inode is maintained by the MSDOS file system	 * for directory and by UMSDOS for other files.  The logic is that	 * MSDOS is already figuring out what to do for directories and	 * does nothing for other files.  For MSDOS, there are no hard links	 * so all file carry nlink==1.  UMSDOS use some info in the	 * EMD file to plug the correct value.	 */	if (!S_ISDIR (entry->mode)) {		if (entry->nlink > 0) {			inode->i_nlink = entry->nlink;		} else {			printk (KERN_ERR 				"UMSDOS:  lookup_patch entry->nlink < 1 ???\n");		}	}	/*	 * The mode may have changed, so patch the inode again.	 */	umsdos_patch_dentry_inode(dentry, info->f_pos);	umsdos_set_dirinfo_new(dentry, info->f_pos);out:	return;}/*

⌨️ 快捷键说明

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