📄 fs.c
字号:
/* * fs.c * NTFS driver for Linux 2.3.x * * Copyright (C) 1995-1997, 1999 Martin von L鰓is * Copyright (C) 1996 Richard Russon * Copyright (C) 1996-1997 R間is Duchesne * Copyright (C) 2000, Anton Altaparmakov */#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef NTFS_IN_LINUX_KERNEL#include <linux/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/uaccess.h>#include <linux/nls.h>#include <linux/locks.h>#include <linux/init.h>#include <linux/smp_lock.h>/* Forward declarations */static struct inode_operations ntfs_dir_inode_operations;static struct file_operations ntfs_dir_operations;#define ITEM_SIZE 2040/* io functions to user space */static void ntfs_putuser(ntfs_io* dest,void *src,ntfs_size_t len){ copy_to_user(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; copy_from_user (dest, p->user, len); p->user += len; p->off += len;}#endifstatic ssize_tntfs_read(struct file * filp, char *buf, size_t count, loff_t *off){ int error; ntfs_io io; ntfs_inode *ino=NTFS_LINO2NINO(filp->f_dentry->d_inode); /* inode is not properly initialized */ if(!ino)return -EINVAL; ntfs_debug(DEBUG_OTHER, "ntfs_read %x,%x,%x ->", (unsigned)ino->i_number,(unsigned)*off,(unsigned)count); /* inode has no unnamed data attribute */ if(!ntfs_find_attr(ino,ino->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(ino,ino->vol->at_data,NULL,*off,&io); if(error && !io.size)return -error; *off+=io.size; return io.size;}#ifdef CONFIG_NTFS_RWstatic ssize_tntfs_write(struct file *filp,const char* buf,size_t count,loff_t *pos){ int ret; ntfs_io io; struct inode *inode = filp->f_dentry->d_inode; ntfs_inode *ino = NTFS_LINO2NINO(inode); struct ntfs_getuser_update_vm_s param; if (!ino) return -EINVAL; ntfs_debug (DEBUG_LINUX, "ntfs_write %x,%x,%x ->\n", (unsigned)ino->i_number, (unsigned)*pos, (unsigned)count); /* Allows to lock fs ro at any time */ if (inode->i_sb->s_flags & MS_RDONLY) return -ENOSPC; if (!ntfs_find_attr(ino,ino->vol->at_data,NULL)) return -EINVAL; /* Evaluating O_APPEND is the file system's job... */ if (filp->f_flags & O_APPEND) *pos = inode->i_size; param.user = buf; param.ino = inode; param.off = *pos; io.fn_put = 0; io.fn_get = ntfs_getuser_update_vm; io.param = ¶m; io.size = count; ret = ntfs_write_attr (ino, ino->vol->at_data, NULL, *pos, &io); ntfs_debug (DEBUG_LINUX, "write -> %x\n", ret); if(ret<0) return -EINVAL; *pos += io.size; if (*pos > inode->i_size) inode->i_size = *pos; mark_inode_dirty (filp->f_dentry->d_inode); 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; int length=NTFS_GETU8(entry+0x50); int inum=NTFS_GETU32(entry); int error;#ifdef NTFS_NGT_NT_DOES_LOWER int i,to_lower=0;#endif 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;#ifdef NTFS_NGT_NT_DOES_LOWER case 3: to_lower=1;#endif } break; case ngt_posix: break; case ngt_full: show_hidden=1; break; } if(!show_hidden && ((NTFS_GETU8(entry+0x48) & 2)==2)){ ntfs_debug(DEBUG_OTHER,"Skipping hidden file\n"); return 0; } nf->name=0; if(ntfs_encodeuni(NTFS_INO2VOL(nf->dir),(ntfs_u16*)(entry+0x52), length,&nf->name,&nf->namelen)){ ntfs_debug(DEBUG_OTHER,"Skipping unrepresentable file\n"); if(nf->name)ntfs_free(nf->name); return 0; } /* Do not return ".", as this is faked */ if(length==1 && *nf->name=='.') return 0;#ifdef NTFS_NGT_NT_DOES_LOWER 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';#endif 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,DT_UNKNOWN); 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 file* filp, void *dirent, filldir_t filldir){ struct ntfs_filldir cb; int error; struct inode *dir=filp->f_dentry->d_inode; ntfs_debug(DEBUG_OTHER, "ntfs_readdir ino %x mode %x\n", (unsigned)dir->i_ino,(unsigned int)dir->i_mode); ntfs_debug(DEBUG_OTHER, "readdir: Looking for file %x dircount %d\n", (unsigned)filp->f_pos,atomic_read(&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,DT_DIR); filp->f_pos=0xFFFF0001; return 0; /* FIXME: parent directory */ case 1: filldir(dirent,"..",2,filp->f_pos,0,DT_DIR); 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{ ntfs_debug(DEBUG_OTHER,"looking for next file\n"); error=ntfs_getdir_unsorted(NTFS_LINO2NINO(dir),&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;}/* Copied from vfat driver */static int simple_getbool(char *s, int *setval){ if (s) { if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true")) { *setval = 1; } else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false")) { *setval = 0; } else { return 0; } } else { *setval = 1; } return 1;}/* Parse the (re)mount options */static int parse_options(ntfs_volume* vol,char *opt){ char *value; vol->uid=vol->gid=0; vol->umask=0077; vol->ngt=ngt_nt; vol->nls_map=0; vol->nct=0; if(!opt)goto done; for(opt = strtok(opt,",");opt;opt=strtok(NULL,",")) { if ((value = strchr(opt, '=')) != NULL) *value++='\0'; if(strcmp(opt,"uid")==0) { if(!value || !*value)goto needs_arg; 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)goto needs_arg; 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)goto needs_arg; vol->umask=simple_strtoul(value,&value,0); if(*value){ printk(KERN_ERR "umask invalid argument\n"); return 0; } }else if(strcmp(opt, "iocharset") == 0){ if(!value || !*value)goto needs_arg; vol->nls_map=load_nls(value); vol->nct |= nct_map; if(!vol->nls_map){ printk(KERN_ERR "NTFS: charset not found"); return 0; } }else if(strcmp(opt, "posix") == 0){ int val; if(!value || !*value)goto needs_arg; if(!simple_getbool(value,&val)) goto needs_bool; vol->ngt=val?ngt_posix:ngt_nt; }else if(strcmp(opt,"utf8") == 0){ int val=0; if(!value || !*value) val=1; else if(!simple_getbool(value,&val)) goto needs_bool; if(val) vol->nct|=nct_utf8; }else if(strcmp(opt,"uni_xlate") == 0){ int val=0; /* no argument: uni_vfat. boolean argument: uni_vfat. "2": uni. */ if(!value || !*value) val=1; else if(strcmp(value,"2")==0) vol->nct |= nct_uni_xlate; else if(!simple_getbool(value,&val)) goto needs_bool; if(val) vol->nct |= nct_uni_xlate_vfat | nct_uni_xlate; }else{ printk(KERN_ERR "NTFS: unkown option '%s'\n", opt); return 0; } } if(vol->nct & nct_utf8 & (nct_map | nct_uni_xlate)){ printk(KERN_ERR "utf8 cannot be combined with iocharset or uni_xlate\n"); return 0; } done: if((vol->nct & (nct_uni_xlate | nct_map | nct_utf8))==0) /* default to UTF-8 */ vol->nct=nct_utf8; if(!vol->nls_map){ vol->nls_map=load_nls_default(); if (vol->nls_map) vol->nct=nct_map | (vol->nct&nct_uni_xlate); } return 1; needs_arg: printk(KERN_ERR "NTFS: %s needs an argument",opt); return 0; needs_bool: printk(KERN_ERR "NTFS: %s needs boolean argument",opt); return 0;} static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d){ struct inode *res=0; char *item=0; ntfs_iterate_s walk; int error; ntfs_debug(DEBUG_NAME1, "Looking up %s in %x\n",d->d_name.name, (unsigned)dir->i_ino); /* convert to wide string */ error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name, d->d_name.len,&walk.name,&walk.namelen); if(error) return ERR_PTR(-error); item=ntfs_malloc(ITEM_SIZE); if( !item ) return ERR_PTR(-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_LINO2NINO(dir); walk.result=item; if(ntfs_getdir_byname(&walk)) { res=iget(dir->i_sb,NTFS_GETU32(item)); } d_add(d,res); ntfs_free(item); ntfs_free(walk.name); /* Always return success, the dcache will handle negative entries. */ return NULL;}static struct file_operations ntfs_file_operations_nommap = { read: ntfs_read,#ifdef CONFIG_NTFS_RW write: ntfs_write,#endif};static struct inode_operations ntfs_inode_operations_nobmap;#ifdef CONFIG_NTFS_RWstatic intntfs_create(struct inode* dir,struct dentry *d,int mode){ struct inode *r=0; ntfs_inode *ino=0; ntfs_volume *vol; int error=0; ntfs_attribute *si; r=new_inode(dir->i_sb); if(!r){ error=ENOMEM; goto fail; } ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n",d->d_name.name); vol=NTFS_INO2VOL(dir);#ifdef NTFS_IN_LINUX_KERNEL ino=NTFS_LINO2NINO(r);#else ino=ntfs_malloc(sizeof(ntfs_inode)); if(!ino){ error=ENOMEM; goto fail; } r->u.generic_ip=ino;#endif error=ntfs_alloc_file(NTFS_LINO2NINO(dir),ino,(char*)d->d_name.name, d->d_name.len); if(error)goto fail; error=ntfs_update_inode(ino); if(error)goto fail; error=ntfs_update_inode(NTFS_LINO2NINO(dir)); if(error)goto fail; r->i_uid=vol->uid; r->i_gid=vol->gid; /* 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_fop=&ntfs_file_operations_nommap, r->i_mode=S_IFREG|S_IRUGO;#ifdef CONFIG_NTFS_RW r->i_mode|=S_IWUGO;#endif r->i_mode &= ~vol->umask; insert_inode_hash(r); d_instantiate(d,r); return 0; fail: #ifndef NTFS_IN_LINUX_KERNEL if(ino)ntfs_free(ino); #endif if(r)iput(r); return -error;}static int_linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -