dir.c

来自「elinux jffs初始版本 具体了解JFFS的文件系统!」· C语言 代码 · 共 1,279 行 · 第 1/2 页

C
1,279
字号
/* *  dir.c * *  Copyright (C) 1995, 1996 by Volker Lendecke * */#include <linux/sched.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/kernel.h>#include <linux/malloc.h>#include <linux/mm.h>#include <linux/ncp_fs.h>#include <asm/segment.h>#include <linux/errno.h>#include <linux/locks.h>#include "ncplib_kernel.h"struct ncp_dirent {	struct nw_info_struct i;	struct nw_search_sequence s; /* given back for i */	unsigned long f_pos;};static int ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);static int ncp_readdir(struct inode *inode, struct file *filp,            void *dirent, filldir_t filldir);static intncp_read_volume_list(struct ncp_server *server, int start_with,		     int cache_size);static intncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,	       int cache_size, struct ncp_dirent *entry);static struct inode *ncp_iget(struct inode *dir, struct nw_file_info *finfo);static struct ncp_inode_info *ncp_find_dir_inode(struct inode *dir, const char *name);static intncp_lookup(struct inode *dir, const char *__name,           int len, struct inode **result);static int ncp_create(struct inode *dir, const char *name, int len, int mode,            struct inode **result);static int ncp_mkdir(struct inode *dir, const char *name, int len, int mode);static int ncp_rmdir(struct inode *dir, const char *name, int len);static intncp_unlink(struct inode *dir, const char *name, int len);static intncp_rename(struct inode *old_dir, const char *old_name, int old_len,            struct inode *new_dir, const char *new_name, int new_len,           int must_be_dir);static inline voidstr_upper(char *name){	while (*name)	{		if (*name >= 'a' && *name <= 'z')		{			*name -= ('a' - 'A');		}		name++;	}}static inline voidstr_lower(char *name){	while (*name)	{		if (*name >= 'A' && *name <= 'Z')		{			*name += ('a' - 'A');		}		name ++;	}}static inline intncp_namespace(struct inode *i){	struct ncp_server *server   = NCP_SERVER(i);	struct nw_info_struct *info = NCP_ISTRUCT(i);	return server->name_space[info->volNumber];}static inline intncp_preserve_case(struct inode *i){	return (ncp_namespace(i) == NW_NS_OS2);}static struct file_operations ncp_dir_operations = {        NULL,			/* lseek - default */	ncp_dir_read,		/* read - bad */	NULL,			/* write - bad */	ncp_readdir,		/* readdir */	NULL,			/* select - default */	ncp_ioctl,		/* ioctl */	NULL,			/* mmap */	NULL,			/* no special open code */	NULL,			/* no special release code */	NULL			/* fsync */};struct inode_operations ncp_dir_inode_operations = {	&ncp_dir_operations,	/* default directory file ops */	ncp_create,		/* create */	ncp_lookup,    		/* lookup */	NULL,			/* link */	ncp_unlink,    		/* unlink */	NULL,			/* symlink */	ncp_mkdir,     		/* mkdir */	ncp_rmdir,     		/* rmdir */	NULL,			/* mknod */	ncp_rename,    		/* rename */	NULL,			/* readlink */	NULL,			/* follow_link */	NULL,			/* bmap */	NULL,			/* truncate */	NULL,			/* permission */	NULL                    /* smap */};/* Here we encapsulate the inode number handling that depends upon the * mount mode: When we mount a complete server, the memory address of * the ncp_inode_info is used as the inode number. When only a single * volume is mounted, then the dirEntNum is used as the inode * number. As this is unique for the complete volume, this should * enable the NFS exportability of a ncpfs-mounted volume. */static inline intncp_single_volume(struct ncp_server *server){	return (server->m.mounted_vol[0] != '\0');}inline ino_tncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info){	return ncp_single_volume(server)		? info->finfo.i.dirEntNum : (ino_t)info;}static inline intncp_is_server_root(struct inode *inode){	struct ncp_server *s = NCP_SERVER(inode);	return (   (!ncp_single_volume(s))		&& (inode->i_ino == ncp_info_ino(s, &(s->root))));}struct ncp_inode_info *ncp_find_inode(struct inode *inode){	struct ncp_server *server = NCP_SERVER(inode);        struct ncp_inode_info *root = &(server->root);        struct ncp_inode_info *this = root;	ino_t ino = inode->i_ino;        do	{                if (ino == ncp_info_ino(server, this))		{			return this;		}		this = this->next;        }	while (this != root);	return NULL;}	static int ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count){	return -EISDIR;}static kdev_t             c_dev = 0;static unsigned long      c_ino = 0;static int                c_size;static int                c_seen_eof;static int                c_last_returned_index;static struct ncp_dirent* c_entry = NULL;static int                c_lock = 0;static struct wait_queue *c_wait = NULL;static inline voidncp_lock_dircache(void){	while (c_lock)		sleep_on(&c_wait);	c_lock = 1;}static inline voidncp_unlock_dircache(void){	c_lock = 0;	wake_up(&c_wait);}static intncp_readdir(struct inode *inode, struct file *filp,            void *dirent, filldir_t filldir){	int result = 0;	int i = 0;        int index = 0;	struct ncp_dirent *entry = NULL;        struct ncp_server *server = NCP_SERVER(inode);	struct ncp_inode_info *dir = NCP_INOP(inode);	DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);	DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",		 inode->i_ino, c_ino);	if (!inode || !S_ISDIR(inode->i_mode))	{		printk("ncp_readdir: inode is NULL or not a directory\n");		return -EBADF;	}	if (!ncp_conn_valid(server))	{		return -EIO;	}	ncp_lock_dircache();	if (c_entry == NULL) 	{		i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;		c_entry = (struct ncp_dirent *) vmalloc(i);		if (c_entry == NULL)		{			printk("ncp_readdir: no MEMORY for cache\n");			result = -ENOMEM;			goto finished;		}	}        if (filp->f_pos == 0)	{                ncp_invalid_dir_cache(inode);		if (filldir(dirent,".",1, filp->f_pos,			    ncp_info_ino(server, dir)) < 0)		{			goto finished;		}		filp->f_pos += 1;        }	if (filp->f_pos == 1)	{		if (filldir(dirent,"..",2, filp->f_pos,			    ncp_info_ino(server, dir->dir)) < 0)		{			goto finished;		}		filp->f_pos += 1;	}	if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))	{		for (i = 0; i < c_size; i++)		{			if (filp->f_pos == c_entry[i].f_pos)			{                                entry = &c_entry[i];                                c_last_returned_index = i;                                index = i;                                break;			}		}                if ((entry == NULL) && c_seen_eof)		{			goto finished;		}	}	if (entry == NULL)	{		int entries;		DDPRINTK("ncp_readdir: Not found in cache.\n");		if (ncp_is_server_root(inode))		{			entries = ncp_read_volume_list(server, filp->f_pos,						       NCP_READDIR_CACHE_SIZE);			DPRINTK("ncp_read_volume_list returned %d\n", entries);		}		else		{			entries = ncp_do_readdir(server, inode, filp->f_pos,						 NCP_READDIR_CACHE_SIZE,						 c_entry);			DPRINTK("ncp_readdir returned %d\n", entries);		}		if (entries < 0)		{			c_dev = 0;			c_ino = 0;			result = entries;			goto finished;		}		if (entries > 0)		{                        c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);			c_dev  = inode->i_dev;			c_ino  = inode->i_ino;			c_size = entries;			entry = c_entry;                        c_last_returned_index = 0;                        index = 0;			if (!ncp_preserve_case(inode))			{				for (i = 0; i < c_size; i++)				{					str_lower(c_entry[i].i.entryName);				}			}		}	}        if (entry == NULL)	{                /* Nothing found, even from a ncp call */		goto finished;        }        while (index < c_size)	{		ino_t ino;		if (ncp_single_volume(server))		{			ino = (ino_t)(entry->i.dirEntNum);		}		else		{			/* For getwd() we have to return the correct			 * inode in d_ino if the inode is currently in			 * use. Otherwise the inode number does not			 * matter. (You can argue a lot about this..) */			struct ncp_inode_info *ino_info;			ino_info = ncp_find_dir_inode(inode,						      entry->i.entryName);			/* Some programs seem to be confused about a			 * zero inode number, so we set it to one.			 * Thanks to Gordon Chaffee for this one. */			if (ino_info == NULL)			{				ino_info = (struct ncp_inode_info *) 1;			}			ino = (ino_t)(ino_info);		}		DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);		DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);                if (filldir(dirent, entry->i.entryName, entry->i.nameLen,                            entry->f_pos, ino) < 0)		{			break;                }		if (   (inode->i_dev != c_dev)		    || (inode->i_ino != c_ino)		    || (entry->f_pos != filp->f_pos))		{			/* Someone has destroyed the cache while we slept			   in filldir */			break;		}                filp->f_pos += 1;                index += 1;                entry += 1;	} finished:	ncp_unlock_dircache();	return result;}static intncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size){	struct ncp_dirent *entry = c_entry;	int total_count = 2;	int i;#if 1	if (fpos < 2)	{		printk("OOPS, we expect fpos >= 2");		fpos = 2;	}#endif	for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++)	{		struct ncp_volume_info info;		if (ncp_get_volume_info_with_number(server, i, &info) != 0)		{			return (total_count - fpos);		}		if (strlen(info.volume_name) > 0)		{			if (total_count < fpos)			{				DPRINTK("ncp_read_volumes: skipped vol: %s\n",					info.volume_name);			}			else if (total_count >= fpos + cache_size)			{				return (total_count - fpos);			}			else			{				DPRINTK("ncp_read_volumes: found vol: %s\n",					info.volume_name);				if (ncp_lookup_volume(server,						      info.volume_name,						      &(entry->i)) != 0)				{					DPRINTK("ncpfs: could not lookup vol "						"%s\n", info.volume_name);					continue;				}				entry->f_pos = total_count;				entry += 1;			}			total_count += 1;		}	}	return (total_count - fpos);}static intncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,	       int cache_size, struct ncp_dirent *entry){	static struct nw_search_sequence seq;	static struct inode *last_dir;	static int total_count;#if 1	if (fpos < 2)	{		printk("OOPS, we expect fpos >= 2");		fpos = 2;	}#endif	DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);	if (fpos == 2)	{		last_dir = NULL;		total_count = 2;	}	if ((fpos != total_count) || (dir != last_dir))	{		total_count = 2;		last_dir = dir;		DPRINTK("ncp_do_readdir: re-used seq for %s\n",			NCP_ISTRUCT(dir)->entryName);		if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0)		{			DPRINTK("ncp_init_search failed\n");			return total_count - fpos;		}	}	while (total_count < fpos + cache_size)	{		if (ncp_search_for_file_or_subdir(server, &seq,						  &(entry->i)) != 0)		{			return total_count - fpos;		}		if (total_count < fpos)		{			DPRINTK("ncp_do_readdir: skipped file: %s\n",				entry->i.entryName);		}		else		{			DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",				 entry->i.entryName, fpos, total_count);			entry->s = seq;			entry->f_pos = total_count;			entry += 1;		}		total_count += 1;	}	return (total_count - fpos);}voidncp_init_dir_cache(void){	c_dev   = 0;        c_ino   = 0;        c_entry = NULL;}voidncp_invalid_dir_cache(struct inode *ino){	if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))	{		c_dev = 0;                c_ino = 0;                c_seen_eof = 0;        }}voidncp_free_dir_cache(void){        DPRINTK("ncp_free_dir_cache: enter\n");                if (c_entry == NULL)	{                return;	}	vfree(c_entry);	c_entry = NULL;        DPRINTK("ncp_free_dir_cache: exit\n");}static struct inode *ncp_iget(struct inode *dir, struct nw_file_info *finfo){	struct inode *inode;        struct ncp_inode_info *new_inode_info;        struct ncp_inode_info *root;	if (dir == NULL)	{		printk("ncp_iget: dir is NULL\n");		return NULL;	}	if (finfo == NULL)	{		printk("ncp_iget: finfo is NULL\n");		return NULL;	}        new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),                                     GFP_KERNEL);        if (new_inode_info == NULL)	{                printk("ncp_iget: could not alloc mem for %s\n",		       finfo->i.entryName);                return NULL;        }        new_inode_info->state = NCP_INODE_LOOKED_UP;        new_inode_info->nused = 0;        new_inode_info->dir   = NCP_INOP(dir);        new_inode_info->finfo = *finfo;        NCP_INOP(dir)->nused += 1;        /* We have to link the new inode_info into the doubly linked           list of inode_infos to make a complete linear search           possible. */        root = &(NCP_SERVER(dir)->root);        new_inode_info->prev = root;        new_inode_info->next = root->next;        root->next->prev = new_inode_info;        root->next = new_inode_info;        	if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),						   new_inode_info))))	{		printk("ncp_iget: iget failed!");		return NULL;	}	return inode;}voidncp_free_inode_info(struct ncp_inode_info *i){        if (i == NULL)	{                printk("ncp_free_inode: i == NULL\n");                return;        }        i->state = NCP_INODE_CACHED;        while ((i->nused == 0) && (i->state == NCP_INODE_CACHED))	{                struct ncp_inode_info *dir = i->dir;

⌨️ 快捷键说明

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