📄 ntfs_fs.c
字号:
/* * ntfs_fs.c * NTFS driver for Linux * * Copyright (C) 1995,1996 Martin von L鰓is * Copyright (C) 1996 Richard Russon * Copyright (C) 1996 Regis Duchesne */#ifdef MODULE#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif /* CONFIG_MODVERSIONS */#include <linux/module.h>#else#define MOD_INC_USE_COUNT#define MOD_DEC_USE_COUNT#endif /* MODULE */#include <stdarg.h>#include <linux/version.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/locks.h>#include <linux/stat.h>#include <linux/mm.h>#include <linux/malloc.h>#include <linux/string.h>#include <errno.h>#if (LINUX_VERSION_CODE > (2*65536 + 256))#include <asm/uaccess.h>#else#include <asm/segment.h>#endif#include "config.h"#include "ntfs.h"#include "version.h"#if (LINUX_VERSION_CODE<(2*65536))#error Please upgrade to Linux 2.0#endif#define ITEM_SIZE 2040#define NAME_SIZE 300extern struct inode_operations ntfs_inode_operations;extern struct inode_operations ntfs_inode_operations_nobmap;extern struct inode_operations ntfs_dir_inode_operations;extern struct super_operations ntfs_super_operations;void ntfs_free(void*);#ifdef DEBUG#define PRINTK(x,args...) printk(x, ##args)#define NTFS_DEBUG(x,args...) ntfs_debug(x, ##args)#else#define PRINTK(x,args...)#define NTFS_DEBUG(x,args...)#endif#define DEBUG_OTHER 1#define DEBUG_MALLOC 2static int ntdebug;/* io functions to user space */static void ntfs_putuser(ntfs_io* dest,void *src,ntfs_size_t len){#if (LINUX_VERSION_CODE > (2*65536 + 256)) copy_to_user(dest->param,src,len);#else memcpy_tofs(dest->param,src,len);#endif dest->param+=len;}static void ntfs_getuser(void *dest,ntfs_io *src,ntfs_size_t len){#if (LINUX_VERSION_CODE > (2*65536 + 256)) copy_from_user(dest,src->param,len);#else memcpy_fromfs(dest,src->param,len);#endif src->param+=len;}void *ntfs_memcpy(void*dest,const void*src,__kernel_size_t len){ return memcpy(dest,src,len);}void ntfs_bzero(void *dest,__kernel_size_t n){ memset(dest,0,n);}int ntfs_strlen(char*s){ return strlen(s);}#if (LINUX_VERSION_CODE > (2*65536 + 256))static long ntfs_read(struct inode* inode, struct file * filp, char *buf, unsigned long count)#elsestatic int ntfs_read(struct inode* inode, struct file * filp, char *buf, int count)#endif{ int ret; ntfs_io io; NTFS_DEBUG("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,AT_DATA,NULL)) return -EINVAL; /* read the data */ io.fn_put=ntfs_putuser; io.fn_get=0; io.param=buf; ret=ntfs_read_attr((ntfs_inode*)inode->u.generic_ip, AT_DATA,NULL,filp->f_pos,&io,count); NTFS_DEBUG("%x\n",ret); if(ret<0)return -EINVAL; filp->f_pos+=ret; return ret;}#if (LINUX_VERSION_CODE > (2*65536 + 256))static long ntfs_write(struct inode* inode, struct file *filp, const char* buf, unsigned long count)#elsestatic int ntfs_write(struct inode* inode, struct file *filp, const char* buf, int count)#endif{ struct super_block* sb; int ret; ntfs_io io; NTFS_DEBUG("ntfs_write %x,%x,%x ->", (unsigned)inode->i_ino,(unsigned)filp->f_pos,(unsigned)count); if(!inode || !inode->u.generic_ip) return -EINVAL; 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,AT_DATA,NULL)) return -EINVAL; io.fn_put=0; io.fn_get=ntfs_getuser; io.param=(void*)buf; /* to get rid of the const */ ret = ntfs_write_attr((ntfs_inode*)inode->u.generic_ip, AT_DATA,NULL,filp->f_pos,&io,count); NTFS_DEBUG("%x\n",ret); if(ret<0)return -EINVAL; filp->f_pos+=ret; return ret;}/* ntfs_read_inode is called by the Virtual File System (the kernel layer that * deals with filesystems) when iget is called requesting an inode not already * present in the inode table. Typically filesystems have separate * inode_operations for directories, files and symlinks. */static void ntfs_read_inode(struct inode* inode){ ntfs_volume *vol; int can_mmap=0; ntfs_inode *ino; ntfs_attribute *data; ntfs_attribute *si; vol=NTFS_INO2VOL(inode); inode->i_op=NULL; inode->i_mode=0; inode->u.generic_ip=NULL; NTFS_DEBUG("ntfs_read_inode %x\n",(unsigned)inode->i_ino); switch(inode->i_ino) { /* those are loaded special files */ case FILE_MFT: ino=NTFS_INO2VOL(inode)->mft_ino;break; default: ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); if(!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),inode->i_ino)==-1) { NTFS_DEBUG("NTFS:Error loading inode %x\n", (unsigned int)inode->i_ino); return; } } inode->u.generic_ip=ino; /* Set uid/gid from mount options */ inode->i_uid=vol->uid; inode->i_gid=vol->gid; inode->i_nlink=1; /* Use the size of the data attribute as file size */ data = ntfs_find_attr(ino,AT_DATA,NULL); if(!data) { inode->i_size=0; can_mmap=0; } else { inode->i_size=DATASIZE(&data->header); can_mmap=!RESIDENT(&data->header) && !COMPRESSED(&data->header); } /* get the file modification times from the standard information */ si=ntfs_find_attr(ino,AT_STANDARD_INFORMATION,NULL); if(si){ char *attr=si->d.data; inode->i_atime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+0x18)); inode->i_ctime=ntfs_ntutc2unixutc(NTFS_GETU64(attr)); inode->i_mtime=ntfs_ntutc2unixutc(NTFS_GETU64(attr+8)); } /* if it has an index root, it's a directory */ if(ntfs_find_attr(ino,AT_INDEX_ROOT,"$I30")) { ntfs_attribute *at; at = ntfs_find_attr (ino, AT_INDEX_ALLOCATION, "$I30"); inode->i_size = at ? DATASIZE(&at->header) : 0; inode->i_op=&ntfs_dir_inode_operations; inode->i_mode=S_IFDIR|S_IRUGO|S_IXUGO; } else { inode->i_op=can_mmap ? &ntfs_inode_operations : &ntfs_inode_operations_nobmap; inode->i_mode=S_IFREG|S_IRUGO|S_IMMUTABLE; inode->i_mode=S_IFREG|S_IRUGO; } inode->i_mode &= ~vol->umask;}struct ntfs_filldir{ struct inode *dir; filldir_t filldir; enum ntfs_getdent_type 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: if((flags & 2)==0) return 0; break; case ngt_nt: if((flags & 1)==0) return 0; if((flags & 2)==2) 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; /* FIXME: utf 8 handling ntfs_uni2ascii(nf->name,entry+0x52,length);*/ 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; dcache_add(nf->dir,nf->name,nf->namelen,inum); NTFS_DEBUG("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); /* 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("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("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("readdir: EOD\n"); return 0; } cb.dir=dir; cb.filldir=filldir; cb.name=ntfs_malloc(NAME_SIZE); 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); ntfs_free(cb.name); filp->f_pos=(cb.ph<<16)|cb.pl; NTFS_DEBUG("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 void ntfs_put_inode(struct inode *ino){ NTFS_DEBUG("ntfs_put_inode %lx\n",ino->i_ino); if(ino->i_ino!=FILE_MFT && ino->u.generic_ip) { ntfs_clear_inode(ino->u.generic_ip); ntfs_free(ino->u.generic_ip); ino->u.generic_ip=0; } clear_inode(ino);}static void ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize){ struct statfs fs; struct inode *bitmap; struct inode *mft; ntfs_volume *vol; NTFS_DEBUG("ntfs_statfs\n"); vol=NTFS_SB2VOL(sb); memset(&fs,0,sizeof(fs)); fs.f_type=NTFS_SUPER_MAGIC; fs.f_bsize=vol->clustersize; fs.f_blocks=ntfs_get_volumesize(NTFS_SB2VOL(sb)); bitmap=iget(sb,FILE_BITMAP); fs.f_bfree=ntfs_get_free_cluster_count((ntfs_inode*)bitmap->u.generic_ip); iput(bitmap); fs.f_bavail=fs.f_bfree; /* Number of files is limited by free space only, so we lie here */ fs.f_ffree=0; mft=iget(sb,FILE_MFT); fs.f_files=mft->i_size/vol->mft_recordsize; iput(mft); /* should be read from volume */ fs.f_namelen=255;#if (LINUX_VERSION_CODE > (2*65536 + 256)) copy_to_user(sf,&fs,bufsize);#else memcpy_tofs(sf,&fs,bufsize);#endif}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 if(strcmp(opt, "ntrw") == 0) { if(value){ printk(KERN_ERR "NTFS: rw doesn't need an argument\n"); return 0; } sb->s_flags &= ~MS_RDONLY; }else{ printk(KERN_ERR "NTFS: unkown option '%s'\n", opt); return 0; } } return 1;} /* Entry point of the filesystem. It is called after when the filesystem is * mounted. Don't use any pointer into options, as the page containing is is * freed after ntfs_read_super returns. */struct super_block * ntfs_read_super(struct super_block *sb, void *options, int silent){ struct buffer_head *bh; int dev=sb->s_dev; int i; ntfs_volume *vol;#if defined(DEBUG) && !defined(MODULE) extern int console_loglevel; console_loglevel=15;#endif NTFS_DEBUG("ntfs_read_super\n"); MOD_INC_USE_COUNT; lock_super(sb); NTFS_DEBUG("lock_super\n"); /* set to read only, user option might reset it */ sb->s_flags |= MS_RDONLY; vol=ntfs_malloc(sizeof(ntfs_volume)); if(!parse_options(sb,vol,(char*)options)){ unlock_super(sb); ntfs_free(vol);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -