📄 fs.c
字号:
/* * fs.c * NTFS driver for Linux 2.0 * * Copyright (C) 1995-1997 Martin von L鰓is * Copyright (C) 1996 Richard Russon * Copyright (C) 1996-1997 R間is Duchesne */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "ntfstypes.h"#include "struct.h"#include "util.h"#include "inode.h"#include "super.h"#include "dir.h"#include "support.h"#include "macros.h"#include "sysctl.h"#include <linux/module.h>#include <asm/segment.h>#include <linux/fs.h>#include <linux/string.h>#include <linux/locks.h>#include <linux/sysctl.h>/* for proc_dointvec using isspace */#include <linux/ctype.h>#define ITEM_SIZE 2040#define NAME_SIZE 300/* io functions to user space */static void ntfs_putuser(ntfs_io* dest,void *src,ntfs_size_t len){ memcpy_tofs(dest->param,src,len); dest->param+=len;}#ifdef CONFIG_NTFS_RWstruct ntfs_getuser_update_vm_s{ const char *user; struct inode *ino; loff_t off;};static void ntfs_getuser_update_vm(void *dest,ntfs_io *src,ntfs_size_t len){ struct ntfs_getuser_update_vm_s *p = src->param; memcpy_fromfs (dest, p->user, len); update_vm_cache (p->ino, p->off, dest, len); p->user += len; p->off += len;}#endifstatic int ntfs_read(struct inode* inode, struct file * filp, char *buf, int count){ int error; ntfs_io io; ntfs_volume *vol=NTFS_INO2VOL(inode); ntfs_debug(DEBUG_OTHER, "ntfs_read %x,%x,%x ->", (unsigned)inode->i_ino,(unsigned)filp->f_pos,(unsigned)count); /* inode is not properly initialized */ if(!inode || !inode->u.generic_ip)return -EINVAL; /* inode has no unnamed data attribute */ if(!ntfs_find_attr((ntfs_inode*)inode->u.generic_ip,vol->at_data,NULL)) return -EINVAL; /* read the data */ io.fn_put=ntfs_putuser; io.fn_get=0; io.param=buf; io.size=count; error=ntfs_read_attr((ntfs_inode*)inode->u.generic_ip, vol->at_data,NULL,filp->f_pos,&io); if(error)return -error; filp->f_pos+=io.size; return io.size;}#ifdef CONFIG_NTFS_RWstatic int ntfs_write(struct inode* inode, struct file *filp, const char* buf, int count){ struct super_block* sb; int ret; ntfs_io io; ntfs_volume* vol=NTFS_INO2VOL(inode); struct ntfs_getuser_update_vm_s param; ntfs_debug(DEBUG_OTHER, "ntfs_write %x,%x,%x ->", (unsigned)inode->i_ino,(unsigned)filp->f_pos,(unsigned)count); if(!inode || !inode->u.generic_ip) return -EINVAL; /* Evaluating O_APPEND is the file system's job... */ if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size; sb = inode->i_sb; /* Allows to lock fs ro at any time */ if(sb->s_flags & MS_RDONLY) return -ENOSPC; if(!ntfs_find_attr(inode->u.generic_ip,vol->at_data,NULL)) return -EINVAL; param.user = buf; param.ino = inode; param.off = filp->f_pos; io.fn_put=0; io.fn_get=ntfs_getuser_update_vm; io.param=¶m; io.size=count; ret = ntfs_write_attr((ntfs_inode*)inode->u.generic_ip, vol->at_data,NULL,filp->f_pos,&io); ntfs_debug(DEBUG_OTHER, "%x\n",ret); if(ret<0)return -EINVAL; filp->f_pos += io.size; if (filp->f_pos > inode->i_size) inode->i_size = filp->f_pos; /* Setting the inode dirty does not work in Linux 2.0, as put_inode will be called before write_inode. Write immediately inode->i_dirt = 1; */ ntfs_update_inode (inode->u.generic_ip); return io.size;}#endifstruct ntfs_filldir{ struct inode *dir; filldir_t filldir; unsigned int type; ntfs_u32 ph,pl; void *dirent; char *name; int namelen;}; static int ntfs_printcb(ntfs_u8 *entry,void *param){ struct ntfs_filldir* nf=param; int flags=NTFS_GETU8(entry+0x51); int show_hidden=0,to_lower=0; int length=min(NTFS_GETU8(entry+0x50),NAME_SIZE); int inum=NTFS_GETU32(entry); int i,error; switch(nf->type){ case ngt_dos: /* Don't display long names */ if((flags & 2)==0) return 0; break; case ngt_nt: /* Don't display short-only names */ switch(flags&3){ case 2: return 0; case 3: to_lower=1; } break; case ngt_posix: break; case ngt_full: show_hidden=1; break; } if(!show_hidden && ((NTFS_GETU8(entry+0x48) & 2)==2)) return 0; nf->name=0; if(ntfs_encodeuni(NTFS_INO2VOL(nf->dir),(ntfs_u16*)(entry+0x52), length,&nf->name,&nf->namelen)) return 0; /* Do not return ".", as this is faked */ if(length==1 && *nf->name=='.') return 0; if(to_lower) for(i=0;i<nf->namelen;i++) /* This supports ASCII only. Since only DOS-only names get converted, and since those are restricted to ASCII, this should be correct */ if(nf->name[i]>='A' && nf->name[i]<='Z') nf->name[i]+='a'-'A'; nf->name[nf->namelen]=0; ntfs_debug(DEBUG_OTHER, "readdir got %s,len %d\n",nf->name,nf->namelen); /* filldir expects an off_t rather than an loff_t. Hope we don't have more than 65535 index records */ error=nf->filldir(nf->dirent,nf->name,nf->namelen, (nf->ph<<16)|nf->pl,inum); ntfs_free(nf->name); /* Linux filldir errors are negative, other errors positive */ return error;}/* readdir returns '..', then '.', then the directory entries in sequence As the root directory contains a entry for itself, '.' is not emulated for the root directory */static int ntfs_readdir(struct inode* dir, struct file *filp, void *dirent, filldir_t filldir){ struct ntfs_filldir cb; int error; ntfs_debug(DEBUG_OTHER, "ntfs_readdir ino %x mode %x\n", (unsigned)dir->i_ino,(unsigned int)dir->i_mode); if(!dir || (dir->i_ino==0) || !S_ISDIR(dir->i_mode))return -EBADF; ntfs_debug(DEBUG_OTHER, "readdir: Looking for file %x dircount %d\n", (unsigned)filp->f_pos,dir->i_count); cb.pl=filp->f_pos & 0xFFFF; cb.ph=filp->f_pos >> 16; /* end of directory */ if(cb.ph==0xFFFF){ /* FIXME: Maybe we can return those with the previous call */ switch(cb.pl){ case 0: filldir(dirent,".",1,filp->f_pos,dir->i_ino); filp->f_pos=0xFFFF0001; return 0; /* FIXME: parent directory */ case 1: filldir(dirent,"..",2,filp->f_pos,0); filp->f_pos=0xFFFF0002; return 0; } ntfs_debug(DEBUG_OTHER, "readdir: EOD\n"); return 0; } cb.dir=dir; cb.filldir=filldir; cb.dirent=dirent; cb.type=NTFS_INO2VOL(dir)->ngt; do{ error=ntfs_getdir_unsorted(dir->u.generic_ip,&cb.ph,&cb.pl, ntfs_printcb,&cb); }while(!error && cb.ph!=0xFFFFFFFF); filp->f_pos=(cb.ph<<16)|cb.pl; ntfs_debug(DEBUG_OTHER, "new position %x\n",(unsigned)filp->f_pos); /* -EINVAL is on user buffer full. This is not considered as an error by sys_getdents */ if(error<0) error=0; /* Otherwise (device error, inconsistent data), switch the sign */ return -error;}static int parse_options(struct super_block *sb,ntfs_volume* vol,char *opt){ char *value; vol->uid=vol->gid=0; vol->umask=0777; vol->ngt=ngt_nt; vol->nct=nct_utf8; if(!opt)return 1; for(opt = strtok(opt,",");opt;opt=strtok(NULL,",")) { if ((value = strchr(opt, '=')) != NULL) *value++='\0'; if(strcmp(opt,"uid")==0) { if(!value || !*value){ printk(KERN_ERR "NTFS: uid needs an argument\n"); return 0; } vol->uid=simple_strtoul(value,&value,0); if(*value){ printk(KERN_ERR "NTFS: uid invalid argument\n"); return 0; } }else if(strcmp(opt, "gid") == 0) { if(!value || !*value){ printk(KERN_ERR "NTFS: gid needs an argument\n"); return 0; } vol->gid=simple_strtoul(value,&value,0); if(*value){ printk(KERN_ERR "gid invalid argument\n"); return 0; } }else if(strcmp(opt, "umask") == 0) { if(!value || !*value){ printk(KERN_ERR "NTFS: umask needs an argument\n"); return 0; } vol->umask=simple_strtoul(value,&value,0); if(*value){ printk(KERN_ERR "umask invalid argument\n"); return 0; } }else if(strcmp(opt, "charset") == 0){ if(!value || !*value){ printk(KERN_ERR "NTFS: charset needs an argument"); return 0; } if(strcmp(value,"iso8859-1") == 0) vol->nct = nct_iso8859_1; else{ printk(KERN_ERR "NTFS: unknown charset"); return 0; } }else if(strcmp(opt, "posix") == 0) vol->ngt=ngt_posix; else if(strcmp(opt, "nt") == 0) vol->ngt=ngt_nt; else if(strcmp(opt, "dos") == 0) vol->ngt=ngt_dos; else if(strcmp(opt, "full") == 0) vol->ngt=ngt_full; else{ printk(KERN_ERR "NTFS: unkown option '%s'\n", opt); return 0; } } return 1;} static int ntfs_lookup(struct inode *dir, const char *name, int len, struct inode **result){ struct inode *res=0; unsigned long ino; char *item=0; ntfs_iterate_s walk; ntfs_volume* vol=NTFS_INO2VOL(dir); int error; ntfs_debug(DEBUG_OTHER, "Looking up %s in %x\n",name,(unsigned)dir->i_ino); if(strncmp(name,".",len)==0){ *result=dir; return 0; } if(dcache_lookup(dir,name,len,&ino)) { if(!(*result = iget(dir->i_sb,ino))) { iput(dir); return -EACCES; } iput(dir); return 0; } if(strncmp(name,"..",len)==0) { /*ntfs_debug(DEBUG_OTHER, ".. not supported\n");*/ /* What if a directory has more than one name? */ /* FIXME: support for segments */ ntfs_attribute *attr=ntfs_find_attr((ntfs_inode*)dir->u.generic_ip, vol->at_file_name,NULL); if(!attr){ ntfs_debug(DEBUG_OTHER, ".. not found\n"); iput(dir); return -ENOENT; } if(!(*result = iget(dir->i_sb,NTFS_GETU32(attr->d.data)))) { iput(dir); return -EACCES; } iput(dir); return 0; } /* convert to wide string */ error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)name,len, &walk.name,&walk.namelen); if(error) return error; item=ntfs_malloc(ITEM_SIZE); if( !item ) return ENOMEM; /* ntfs_getdir will place the directory entry into item, and the first long long is the MFT record number */ walk.type=BY_NAME; walk.dir=(ntfs_inode*)dir->u.generic_ip; walk.result=item; if(ntfs_getdir_byname(&walk)) { res=iget(dir->i_sb,NTFS_GETU32(item)); dcache_add(dir, name, len, NTFS_GETU32(item)); } iput(dir); *result=res; ntfs_free(item); ntfs_free(walk.name); return res?0:-ENOENT;}struct file_operations ntfs_file_operations_nommap = { NULL, /* lseek */ ntfs_read,#ifdef CONFIG_NTFS_RW ntfs_write,#else NULL,#endif NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ NULL, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL /* revalidate */};struct inode_operations ntfs_inode_operations_nobmap = { &ntfs_file_operations_nommap, NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */};#ifdef CONFIG_NTFS_RWstatic intntfs_create(struct inode* dir,const char* name,int namelen, int mode,struct inode** result){ struct inode *r=0; ntfs_inode *ino=0; ntfs_volume *vol; int error=0; ntfs_attribute *si; r=get_empty_inode(); if(!r){ error=ENOMEM; goto fail; } ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n",name); vol=NTFS_INO2VOL(dir); ino=ntfs_malloc(sizeof(ntfs_inode)); if(!ino){ error=ENOMEM; goto fail; } error=ntfs_alloc_file(dir->u.generic_ip,ino,(char*)name,namelen); if(error)goto fail; error=ntfs_update_inode(ino); if(error)goto fail; error=ntfs_update_inode(dir->u.generic_ip); if(error)goto fail; r->u.generic_ip=ino; r->i_uid=vol->uid; r->i_gid=vol->gid; r->i_nlink=1; r->i_sb=dir->i_sb; /* FIXME: dirty? dev? */ /* get the file modification times from the standard information */ si=ntfs_find_attr(ino,vol->at_standard_information,NULL); if(si){ char *attr=si->d.data; r->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18)); r->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr)); r->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8)); } /* It's not a directory */ r->i_op=&ntfs_inode_operations_nobmap; r->i_mode=S_IFREG|S_IRUGO;#ifdef CONFIG_NTFS_RW r->i_mode |= S_IWUGO;#endif r->i_mode &= ~vol->umask; *result=r; iput(dir); return 0; fail: if(ino)ntfs_free(ino); if(r)iput(r); iput(dir); return -error;}static int_linux_ntfs_mkdir(struct inode *dir, const char *name, int len, int mode){ int error; ntfs_inode ino; ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n", name, dir->i_ino); error = ENAMETOOLONG; if (len > /* FIXME */255) goto out; error = ntfs_mkdir(dir->u.generic_ip, name, len, &ino); if (error) goto out; dcache_add (dir, name, len, ino.i_number); ntfs_clear_inode (&ino); iput (dir); out: ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", -error); return -error;}#endifstatic int ntfs_bmap(struct inode *ino,int block){ int ret=ntfs_vcn_to_lcn((ntfs_inode*)ino->u.generic_ip,block); ntfs_debug(DEBUG_OTHER, "bmap of %lx,block %x is %x\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -