📄 dir.c
字号:
void * buf, const char * name, int name_len, off_t offset, ino_t ino){ struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf; d->f_pos = offset; d->ino = ino; return 0;}struct UMSDOS_DIR_SEARCH{ struct umsdos_dirent *entry; int found; ino_t search_ino;};static int umsdos_dir_search ( void * buf, const char * name, int name_len, off_t offset, ino_t ino){ int ret = 0; struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf; if (d->search_ino == ino){ d->found = 1; memcpy (d->entry->name,name,name_len); d->entry->name[name_len] = '\0'; d->entry->name_len = name_len; ret = 1; /* So fat_readdir will terminate */ } return ret;}/* Locate entry of an inode in a directory. Return 0 or a negative error code. Normally, this function must succeed. It means a strange corruption in the file system if not.*/int umsdos_inode2entry ( struct inode *dir, struct inode *inode, struct umsdos_dirent *entry) /* Will hold the entry */{ int ret = -ENOENT; if (inode == pseudo_root){ /* Quick way to find the name. Also umsdos_readdir_x won't show /linux anyway */ memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1); entry->name_len = UMSDOS_PSDROOT_LEN; ret = 0; }else{ struct inode *emddir = umsdos_emd_dir_lookup(dir,0); iput (emddir); if (emddir == NULL){ /* This is a DOS directory */ struct UMSDOS_DIR_SEARCH bufk; struct file filp; filp.f_reada = 1; filp.f_pos = 0; bufk.entry = entry; bufk.search_ino = inode->i_ino; fat_readdir (dir,&filp,&bufk,umsdos_dir_search); if (bufk.found){ ret = 0; inode->u.umsdos_i.i_dir_owner = dir->i_ino; inode->u.umsdos_i.i_emd_owner = 0; umsdos_setup_dir_inode(inode); } }else{ /* skip . and .. see umsdos_readdir_x() */ struct file filp; filp.f_reada = 1; filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; while (1){ struct UMSDOS_DIRENT_K bufk; if (umsdos_readdir_x(dir,&filp,&bufk ,1,entry,0,umsdos_filldir_k) < 0){ printk ("UMSDOS: can't locate inode %ld in EMD file???\n" ,inode->i_ino); break; }else if (bufk.ino == inode->i_ino){ ret = 0; umsdos_lookup_patch (dir,inode,entry,bufk.f_pos); break; } } } } return ret;}/* Locate the parent of a directory and the info on that directory Return 0 or a negative error code.*/static int umsdos_locate_ancestor ( struct inode *dir, struct inode **result, struct umsdos_dirent *entry){ int ret; umsdos_patch_inode (dir,NULL,0); ret = umsdos_real_lookup (dir,"..",2,result); PRINTK (("result %d %p ",ret,*result)); if (ret == 0){ struct inode *adir = *result; ret = umsdos_inode2entry (adir,dir,entry); } PRINTK (("\n")); return ret;}/* Build the path name of an inode (relative to the file system. This function is need to set (pseudo) hard link. It uses the same strategy as the standard getcwd().*/int umsdos_locate_path ( struct inode *inode, char *path){ int ret = 0; struct inode *dir = inode; char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL); if (bpath == NULL){ ret = -ENOMEM; }else{ struct umsdos_dirent entry; char *ptbpath = bpath+PATH_MAX-1; *ptbpath = '\0'; PRINTK (("locate_path mode %x ",inode->i_mode)); if (!S_ISDIR(inode->i_mode)){ ret = umsdos_get_dirowner (inode,&dir); PRINTK (("locate_path ret %d ",ret)); if (ret == 0){ ret = umsdos_inode2entry (dir,inode,&entry); if (ret == 0){ ptbpath -= entry.name_len; memcpy (ptbpath,entry.name,entry.name_len); PRINTK (("ptbpath :%s: ",ptbpath)); } } }else{ dir->i_count++; } if (ret == 0){ while (dir != dir->i_sb->s_mounted){ struct inode *adir; ret = umsdos_locate_ancestor (dir,&adir,&entry); iput (dir); dir = NULL; PRINTK (("ancestor %d ",ret)); if (ret == 0){ *--ptbpath = '/'; ptbpath -= entry.name_len; memcpy (ptbpath,entry.name,entry.name_len); dir = adir; PRINTK (("ptbpath :%s: ",ptbpath)); }else{ break; } } } strcpy (path,ptbpath); kfree (bpath); } PRINTK (("\n")); iput (dir); return ret;}/* Return != 0 if an entry is the pseudo DOS entry in the pseudo root.*/int umsdos_is_pseudodos ( struct inode *dir, const char *name, int len){ /* #Specification: pseudo root / DOS hard coded The pseudo sub-directory DOS in the pseudo root is hard coded. The name is DOS. This is done this way to help standardised the umsdos layout. The idea is that from now on /DOS is a reserved path and nobody will think of using such a path for a package. */ return dir == pseudo_root && len == 3 && name[0] == 'D' && name[1] == 'O' && name[2] == 'S';}/* Check if a file exist in the current directory. Return 0 if ok, negative error code if not (ex: -ENOENT).*/static int umsdos_lookup_x ( struct inode *dir, const char *name, int len, struct inode **result, /* Will hold inode of the file, if successful */ int nopseudo) /* Don't care about pseudo root mode */{ int ret = -ENOENT; *result = NULL; umsdos_startlookup(dir); if (len == 1 && name[0] == '.'){ *result = dir; dir->i_count++; ret = 0; }else if (len == 2 && name[0] == '.' && name[1] == '.'){ if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){ /* #Specification: pseudo root / .. in real root Whenever a lookup is those in the real root for the directory .., and pseudo root is active, the pseudo root is returned. */ ret = 0; *result = pseudo_root; pseudo_root->i_count++; }else{ /* #Specification: locating .. / strategy We use the msdos filesystem to locate the parent directory. But it is more complicated than that. We have to step back even further to get the parent of the parent, so we can get the EMD of the parent of the parent. Using the EMD file, we can locate all the info on the parent, such a permissions and owner. */ ret = umsdos_real_lookup (dir,"..",2,result); PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result)); if (ret == 0 && *result != dir->i_sb->s_mounted && *result != pseudo_root){ struct inode *aadir; struct umsdos_dirent entry; ret = umsdos_locate_ancestor (*result,&aadir,&entry); iput (aadir); } } }else if (umsdos_is_pseudodos(dir,name,len)){ /* #Specification: pseudo root / lookup(DOS) A lookup of DOS in the pseudo root will always succeed and return the inode of the real root. */ *result = dir->i_sb->s_mounted; (*result)->i_count++; ret = 0; }else{ struct umsdos_info info; ret = umsdos_parse (name,len,&info); if (ret == 0) ret = umsdos_findentry (dir,&info,0); PRINTK (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret ,info.fake.len)); if (ret == 0){ /* #Specification: umsdos / lookup A lookup for a file is done in two step. First, we locate the file in the EMD file. If not present, we return an error code (-ENOENT). If it is there, we repeat the operation on the msdos file system. If this fails, it means that the file system is not in sync with the emd file. We silently remove this entry from the emd file, and return ENOENT. */ struct inode *inode; ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result); inode = *result; if (inode == NULL){ printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n" ,info.fake.fname); umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode)); }else{ umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); PRINTK (("lookup ino %ld flags %d\n",inode->i_ino ,info.entry.flags)); if (info.entry.flags & UMSDOS_HLINK){ ret = umsdos_hlink2inode (inode,result); } if (*result == pseudo_root && !nopseudo){ /* #Specification: pseudo root / dir lookup For the same reason as readdir, a lookup in /DOS for the pseudo root directory (linux) will fail. */ /* This has to be allowed for resolving hard link which are recorded independently of the pseudo-root mode. */ iput (pseudo_root); *result = NULL; ret = -ENOENT; } } } } umsdos_endlookup(dir); iput (dir); return ret;}/* Check if a file exist in the current directory. Return 0 if ok, negative error code if not (ex: -ENOENT).*/int UMSDOS_lookup ( struct inode *dir, const char *name, int len, struct inode **result) /* Will hold inode of the file, if successful */{ return umsdos_lookup_x(dir,name,len,result,0);}/* Locate the inode pointed by a (pseudo) hard link Return 0 if ok, a negative error code if not.*/int umsdos_hlink2inode (struct inode *hlink, struct inode **result){ int ret = -EIO; char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); *result = NULL; if (path == NULL){ ret = -ENOMEM; iput (hlink); }else{ struct file filp; filp.f_reada = 1; filp.f_pos = 0; PRINTK (("hlink2inode ")); if (umsdos_file_read_kmem (hlink,&filp,path,hlink->i_size) ==hlink->i_size){ struct inode *dir; char *pt = path; dir = hlink->i_sb->s_mounted; path[hlink->i_size] = '\0'; iput (hlink); dir->i_count++; while (1){ char *start = pt; int len; while (*pt != '\0' && *pt != '/') pt++; len = (int)(pt - start); if (*pt == '/') *pt++ = '\0'; if (dir->u.umsdos_i.i_emd_dir == 0){ /* This is a DOS directory */ ret = umsdos_rlookup_x(dir,start,len,result,1); }else{ ret = umsdos_lookup_x(dir,start,len,result,1); } PRINTK (("h2n lookup :%s: -> %d ",start,ret)); if (ret == 0 && *pt != '\0'){ dir = *result; }else{ break; } } }else{ iput (hlink); } PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result)); kfree (path); } return ret;}static struct file_operations umsdos_dir_operations = { NULL, /* lseek - default */ UMSDOS_dir_read, /* read */ NULL, /* write - bad */ UMSDOS_readdir, /* readdir */ NULL, /* select - default */ UMSDOS_ioctl_dir, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* no special release code */ NULL /* fsync */};struct inode_operations umsdos_dir_inode_operations = { &umsdos_dir_operations, /* default directory file-ops */ UMSDOS_create, /* create */ UMSDOS_lookup, /* lookup */ UMSDOS_link, /* link */ UMSDOS_unlink, /* unlink */ UMSDOS_symlink, /* symlink */ UMSDOS_mkdir, /* mkdir */ UMSDOS_rmdir, /* rmdir */ UMSDOS_mknod, /* mknod */ UMSDOS_rename, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL /* permission */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -