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 + -
显示快捷键?