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

📄 emd.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  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 <linux/dcache.h>#include <linux/pagemap.h>#include <asm/delay.h>static void copy_entry(struct umsdos_dirent *p, struct umsdos_dirent *q){	p->name_len = q->name_len;	p->name[p->name_len]='\0';	p->flags = q->flags;	p->nlink = le16_to_cpu (q->nlink);	/* FIXME -- 32bit UID/GID issues */	p->uid = le16_to_cpu (q->uid);	p->gid = le16_to_cpu (q->gid);	p->atime = le32_to_cpu (q->atime);	p->mtime = le32_to_cpu (q->mtime);	p->ctime = le32_to_cpu (q->ctime);	p->rdev = le16_to_cpu (q->rdev);	p->mode = le16_to_cpu (q->mode);}/* * Lookup the EMD dentry for a directory. * * Note: the caller must hold a lock on the parent directory. */struct dentry *umsdos_get_emd_dentry(struct dentry *parent){	struct dentry *demd;	demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE, 					UMSDOS_EMD_NAMELEN, 1);	return demd;}/* * Check whether a directory has an EMD file. * * Note: the caller must hold a lock on the parent directory. */int umsdos_have_emd(struct dentry *dir){	struct dentry *demd = umsdos_get_emd_dentry (dir);	int found = 0;	if (!IS_ERR(demd)) {		if (demd->d_inode)			found = 1;		dput(demd);	}	return found;}/* * Create the EMD file for a directory if it doesn't * already exist. Returns 0 or an error code. * * Note: the caller must hold a lock on the parent directory. */int umsdos_make_emd(struct dentry *parent){	struct dentry *demd = umsdos_get_emd_dentry(parent);	int err = PTR_ERR(demd);	if (IS_ERR(demd)) {		printk("umsdos_make_emd: can't get dentry in %s, err=%d\n",			parent->d_name.name, err);		goto out;	}	/* already created? */	err = 0;	if (demd->d_inode)		goto out_set;Printk(("umsdos_make_emd: creating EMD %s/%s\n",parent->d_name.name, demd->d_name.name));	err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);	if (err) {		printk (KERN_WARNING			"umsdos_make_emd: create %s/%s failed, err=%d\n",			parent->d_name.name, demd->d_name.name, err);	}out_set:	dput(demd);out:	return err;}/* * Read an entry from the EMD file. * Support variable length record. * Return -EIO if error, 0 if OK. * * does not change {d,i}_count */int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_dirent *entry){	struct address_space *mapping = demd->d_inode->i_mapping;	struct page *page;	struct umsdos_dirent *p;	int offs = *pos & ~PAGE_CACHE_MASK;	int recsize;	int ret = 0;	page = read_cache_page(mapping, *pos>>PAGE_CACHE_SHIFT,			(filler_t*)mapping->a_ops->readpage, NULL);	if (IS_ERR(page))		goto sync_fail;	wait_on_page(page);	if (!Page_Uptodate(page))		goto async_fail;	p = (struct umsdos_dirent*)(kmap(page)+offs);	/* if this is an invalid entry (invalid name length), ignore it */	if( p->name_len > UMSDOS_MAXNAME )	{		printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len);		p->name_len = 0; 		ret = -ENAMETOOLONG; /* notify umssync(8) code that something is wrong */	}	recsize = umsdos_evalrecsize(p->name_len);	if (offs + recsize > PAGE_CACHE_SIZE) {		struct page *page2;		int part = (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare;		page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT),				(filler_t*)mapping->a_ops->readpage, NULL);		if (IS_ERR(page2)) {			kunmap(page);			page_cache_release(page);			page = page2;			goto sync_fail;		}		wait_on_page(page2);		if (!Page_Uptodate(page2)) {			kunmap(page);			page_cache_release(page2);			goto async_fail;		}		memcpy(entry->spare,p->spare,part);		memcpy(entry->spare+part,kmap(page2),				recsize+offs-PAGE_CACHE_SIZE);		kunmap(page2);		page_cache_release(page2);	} else		memcpy(entry->spare,p->spare,((char*)p+recsize)-p->spare);	copy_entry(entry, p);	kunmap(page);	page_cache_release(page);	*pos += recsize;	return ret;async_fail:	page_cache_release(page);	page = ERR_PTR(-EIO);sync_fail:	return PTR_ERR(page);}/* * Write an entry in the EMD file. * Return 0 if OK, -EIO if some error. * * Note: the caller must hold a lock on the parent directory. */int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,				int free_entry){	struct inode *dir = parent->d_inode;	struct umsdos_dirent *entry = &info->entry;	struct dentry *emd_dentry;	int ret;	struct umsdos_dirent entry0,*p;	struct address_space *mapping;	struct page *page, *page2 = NULL;	int offs;	emd_dentry = umsdos_get_emd_dentry(parent);	ret = PTR_ERR(emd_dentry);	if (IS_ERR(emd_dentry))		goto out;	/* make sure there's an EMD file */	ret = -EIO;	if (!emd_dentry->d_inode) {		printk(KERN_WARNING			"umsdos_writeentry: no EMD file in %s/%s\n",			parent->d_parent->d_name.name, parent->d_name.name);		goto out_dput;	}	if (free_entry) {		/* #Specification: EMD file / empty entries		 * Unused entries in the EMD file are identified		 * 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 files.		 */		memset (entry->spare, 0, sizeof (entry->spare));	}	/* write the entry and update the parent timestamps */	mapping = emd_dentry->d_inode->i_mapping;	offs = info->f_pos & ~PAGE_CACHE_MASK;	ret = -ENOMEM;	page = grab_cache_page(mapping, info->f_pos>>PAGE_CACHE_SHIFT);	if (!page)		goto out_dput;	p = (struct umsdos_dirent *) (page_address(page) + offs);	if (offs + info->recsize > PAGE_CACHE_SIZE) {		ret = mapping->a_ops->prepare_write(NULL,page,offs,					PAGE_CACHE_SIZE);		if (ret)			goto out_unlock;		page2 = grab_cache_page(mapping,					(info->f_pos>>PAGE_CACHE_SHIFT)+1);		if (!page2)			goto out_unlock2;		ret = mapping->a_ops->prepare_write(NULL,page2,0,					offs+info->recsize-PAGE_CACHE_SIZE);		if (ret)			goto out_unlock3;		p->name_len = entry->name_len;		p->flags = entry->flags;		p->nlink = cpu_to_le16(entry->nlink);		p->uid = cpu_to_le16(entry->uid);		p->gid = cpu_to_le16(entry->gid);		p->atime = cpu_to_le32(entry->atime);		p->mtime = cpu_to_le32(entry->mtime);		p->ctime = cpu_to_le32(entry->ctime);		p->rdev = cpu_to_le16(entry->rdev);		p->mode = cpu_to_le16(entry->mode);		memcpy(p->name,entry->name,			(char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare);		memcpy(page_address(page2),				entry->spare+PAGE_CACHE_SIZE-offs,				offs+info->recsize-PAGE_CACHE_SIZE);		ret = mapping->a_ops->commit_write(NULL,page2,0,					offs+info->recsize-PAGE_CACHE_SIZE);		if (ret)			goto out_unlock3;		ret = mapping->a_ops->commit_write(NULL,page,offs,					PAGE_CACHE_SIZE);		UnlockPage(page2);		page_cache_release(page2);		if (ret)			goto out_unlock;	} else {		ret = mapping->a_ops->prepare_write(NULL,page,offs,					offs + info->recsize);		if (ret)			goto out_unlock;		p->name_len = entry->name_len;		p->flags = entry->flags;		p->nlink = cpu_to_le16(entry->nlink);		p->uid = cpu_to_le16(entry->uid);		p->gid = cpu_to_le16(entry->gid);		p->atime = cpu_to_le32(entry->atime);		p->mtime = cpu_to_le32(entry->mtime);		p->ctime = cpu_to_le32(entry->ctime);		p->rdev = cpu_to_le16(entry->rdev);		p->mode = cpu_to_le16(entry->mode);		memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare);		ret = mapping->a_ops->commit_write(NULL,page,offs,					offs + info->recsize);		if (ret)			goto out_unlock;	}	UnlockPage(page);	page_cache_release(page);			dir->i_ctime = dir->i_mtime = CURRENT_TIME;	mark_inode_dirty(dir);out_dput:	dput(emd_dentry);out:	Printk (("umsdos_writeentry /mn/: returning %d...\n", ret));	return ret;out_unlock3:	UnlockPage(page2);	page_cache_release(page2);out_unlock2:	ClearPageUptodate(page);	kunmap(page);out_unlock:	UnlockPage(page);	page_cache_release(page);	printk ("UMSDOS:  problem with EMD file:  can't write\n");	goto out_dput;}/* * 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). *  * 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

⌨️ 快捷键说明

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