📄 ntfs_vnops.c
字号:
#include <sys/param.h>#include <sys/kernel.h>#include <sys/vnode.h>#include <sys/dirent.h>#include <sys/namei.h>#include <sys/mount.h>#include <sys/systm.h>#include "ntfstypes.h"#include "struct.h"#include "macros.h"#include "util.h"#include "inode.h"#include "super.h"#include "support.h"#include "dir.h"/* Helper */void ntfs_putuser(ntfs_io* dest,void *src,size_t n){ uiomove(src,n,(struct uio*)(dest->param));}/* vnode operations */intntfs_open(ap) struct vop_open_args /* { struct vnode *a_vp; int a_mode; struct ucred *a_cred; struct proc *a_p; }*/ *ap;{ /* Check append-only, etc */ return 0;}int ntfs_close(ap) struct vop_close_args /* { struct vnode *a_vp; int a_fflag; struct ucred *a_cred; struct proc *a_p; } */ *ap;{ /* write back time stamps */ return 0;}int ntfs_access(ap) struct vop_access_args /* { struct vnode *a_vp; int a_mode; struct ucred *a_cred; struct proc *a_p; } */ *ap;{ struct vnode *vp = ap->a_vp; mode_t mask,mode = ap->a_mode; struct ucred *cred = ap->a_cred; ntfs_volume *vol = NTFS_V2INO(vp)->vol; int i; gid_t *gp; if (mode & VWRITE) { switch (vp->v_type) { case VDIR: case VLNK: case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; default: break; } } /* FIXME missing checks: quota, immutable */ if (cred->cr_uid == 0) /* root gets always access */ return 0; /* build the required mask */ mask=0; if (cred->cr_uid == vol->uid) { if (mode & VEXEC) mask |= S_IXUSR; if (mode & VREAD) mask |= S_IRUSR; if (mode & VWRITE) mask |= S_IWUSR; if (vol->umask & mask) return EACCES; } for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) if (vol->gid == *gp) { if (mode & VEXEC) mask |= S_IXGRP; if (mode & VREAD) mask |= S_IRGRP; if (mode & VWRITE) mask |= S_IWGRP; if (vol->umask & mask) return EACCES; } if (mode & VEXEC) mask |= S_IXOTH; if (mode & VREAD) mask |= S_IROTH; if (mode & VWRITE) mask |= S_IWOTH; if (vol->umask & mask) return EACCES; return 0;}intntfs_getattr(ap) struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap; struct ucred *a_cred; struct proc *a_p; } */ *ap;{ ntfs_inode *ino = NTFS_V2INO(ap->a_vp); ntfs_volume *vol = ino->vol; struct vattr *vap = ap->a_vap; ntfs_attribute *si,*data; vap->va_type = ap->a_vp->v_type; vap->va_mode = 0; switch(ap->a_vp->v_type) { case VDIR: vap->va_mode |= S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; break; case VREG: vap->va_mode |= S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; break; default: panic("Unknown device type\n"); break; } vap->va_mode &= ~ino->vol->umask; vap->va_nlink = 1; /* FIXME */ vap->va_uid = ino->vol->uid; vap->va_gid = ino->vol->gid; vap->va_fsid = ino->vol->rdev; vap->va_fileid = ino->i_number; if((data=ntfs_find_attr(ino,vol->at_data,NULL))) vap->va_size = data->size; else vap->va_size = 0; vap->va_blocksize = ino->vol->clustersize; si=ntfs_find_attr(ino,vol->at_standard_information,NULL); if(si) { char *attr=si->d.data;#if 0 /* no FPU allowed here */ vap->va_atime.ts_sec = ntfs_ntutc2unixutc(*(long long*)(attr+0x18)); vap->va_mtime.ts_sec = ntfs_ntutc2unixutc(*(long long*)(attr+8)); vap->va_ctime.ts_sec = ntfs_ntutc2unixutc(*(long long*)(attr));#else vap->va_atime.tv_sec = 0; vap->va_mtime.tv_sec = 0; vap->va_ctime.tv_sec = 0;#endif /* FIXME: ts_nsec */ } vap->va_gen = 0; /* FIXME */ vap->va_flags = 0; vap->va_rdev = VNOVAL; vap->va_bytes = vap->va_size; /* FIXME: allocated size */ vap->va_filerev = VNOVAL; /* vap->va_vaflags unused */ /* vap->va_spare unused */ return 0;}intntfs_read(ap) struct vop_read_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; struct ucred *a_cred; } */ *ap;{ int error=0,ret; struct uio *uio = ap->a_uio; struct ntfs_inode *ino = NTFS_V2INO(ap->a_vp); ntfs_volume *vol = ino->vol; ntfs_io io; ntfs_debug(DEBUG_BSD,"ntfs_read\n"); /* no data requested */ if(uio->uio_resid==0) return 0; if(uio->uio_offset<0) return EINVAL; /* reading directories is not supported */ if(ap->a_vp->v_type == VDIR) return EISDIR; if(!ino || !ntfs_find_attr(ino,vol->at_data,0)) return EINVAL; /* move data */ io.fn_put=ntfs_putuser; io.fn_get=0; io.param=uio; io.size=uio->uio_resid; ret=ntfs_read_attr(ino,vol->at_data,0,uio->uio_offset,&io); if(ret<0) return EINVAL; return error;}intntfs_ioctl(ap) struct vop_ioctl_args /* { struct vnode *a_vp; int a_command; caddr_t a_data; int a_fflag; struct ucred *a_cred; struct proc *a_p; } */ *ap;{ return ENOTTY;}intntfs_select(ap) struct vop_select_args /* { struct vnode *a_vp; int a_which; int a_fflags; struct ucred *a_cred; struct proc *a_p; } */ *ap;{ /* * We should really check to see if I/O is possible. */ return 1;}/* mmap currently not used by BSD *//* later: seek */struct ntfs_readdir{ ntfs_volume *vol; /* filldir_t filldir;*/ /* unsigned int type;*/ struct uio* uio; struct dirent *entry;};static int ntfs_printcb(ntfs_u8* entry, void *param){ struct ntfs_readdir *snr=param; char *name; int namelen; int error=0; int length=NTFS_GETU8(entry+0x50); ntfs_debug(DEBUG_DIR2,"Got entry\n"); if((signed)sizeof(struct dirent)>snr->uio->uio_resid) /* reached end of user memory */ return -1; /* FIXME: suppress unwanted names */ if(ntfs_encodeuni(snr->vol,(ntfs_u16*)(entry+0x52), length,&name,&namelen)) /* just skip the entry */ return 0; ntfs_debug(DEBUG_DIR2,"GOT (%p,%d),%s\n",name,length,name); /* don't return . */ if(length==1 && name[0]=='.') goto err_free; /* don't return oversized names */ if(length > MAXNAMLEN) goto err_free; /* FIXME: lower case conversion */ /* now fill the entry */ snr->entry->d_fileno=NTFS_GETU32(entry); snr->entry->d_namlen=length; ntfs_memmove(snr->entry->d_name,name,length); snr->entry->d_name[length]='\0'; /* and pass it to the user */ error=uiomove((caddr_t)(snr->entry),sizeof(struct dirent),snr->uio); ntfs_debug(DEBUG_DIR1,"return (%d)%s\n",length,name); err_free: ntfs_free(name); return error;}intntfs_readdir(ap) struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; int *a_eofflag; u_int *a_cookies; int a_ncookies; } */ *ap; { int error=0; struct ntfs_inode *ino = NTFS_V2INO(ap->a_vp); struct uio *uio = ap->a_uio; char *item; struct dirent *entry; long long offs; struct ntfs_readdir snr; ntfs_u32 pl,ph; ntfs_debug(DEBUG_BSD,"readdir %x offset %x%x, amount %d\n", (u_int)ino->i_number, (u_int)(uio->uio_offset>>32), (u_int)(uio->uio_offset),uio->uio_resid); /* dir checking should have been done */ /* cookies not supported */ if(ap->a_eofflag || ap->a_cookies || ap->a_ncookies) { printf("ntfs: cookies not supported\n"); return EOPNOTSUPP; } entry=ntfs_malloc(sizeof(struct dirent)); entry->d_reclen=sizeof(struct dirent); /* FIXME: better type reporting */ entry->d_type=DT_UNKNOWN; snr.vol=ino->vol; snr.uio=uio; snr.entry=entry; ph=uio->uio_offset >> 16; pl=uio->uio_offset & 0xFFFF; ntfs_debug(DEBUG_DIR2,"readdir %x %x\n",ph,pl); while(ph!=0xFFFFFFFF){ /* not at end of dir */ error=ntfs_getdir_unsorted(ino,&ph,&pl,ntfs_printcb,&snr); if(error==-1){ /*user buffer full, success*/ error=0; goto setoffset; } if(error) /* fail the entire operation */ goto out; } /* fake .. */ if(pl==0 && uio->uio_resid>=sizeof(struct dirent)) { entry->d_fileno=5; /* FIXME */ entry->d_type=DT_DIR; entry->d_namlen=2; strcpy(entry->d_name,".."); error=uiomove((caddr_t)entry,sizeof(struct dirent),uio); if(error)goto out; pl=1; } if(pl==1 && uio->uio_resid>=sizeof(struct dirent)){ /* return . */ entry->d_fileno=5; /* FIXME */ entry->d_namlen=1; strcpy(entry->d_name,"."); error=uiomove((caddr_t)entry,sizeof(struct dirent),uio); if(error)goto out; pl=2; } setoffset: uio->uio_offset=(((off_t)ph)<<16)|pl; out: ntfs_free(entry); return error;}intntfs_lookup(ap) struct vop_lookup_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; } */ *ap; {#define ITEM_SIZE 2050 int error=0; struct ntfs_inode *dir = NTFS_V2INO(ap->a_dvp); struct componentname *cnp = ap->a_cnp; char *item=0; struct ntfs_iterate_s walk; if(ap->a_dvp->v_type != VDIR) return ENOTDIR; switch(cnp->cn_nameiop) { case CREATE:case RENAME:case DELETE: printf("not supported\n"); return EOPNOTSUPP; } /* check credentials */ /* check name cache */ /* check .,.. */ item=ntfs_malloc(ITEM_SIZE); /* ntfs_getdir will place the directory entry into item, and the first long long is the MFT record number */ error=ntfs_decodeuni(dir->vol,cnp->cn_nameptr,cnp->cn_namelen, &walk.name,&walk.namelen); if(error) return error; walk.type=BY_NAME; walk.dir=dir; walk.result=item; if(ntfs_getdir_byname(&walk)) { error=VFS_VGET(ap->a_dvp->v_mount,NTFS_GETU32(item),ap->a_vpp); if(error) { ntfs_free(item); return error; } if(!(cnp->cn_flags & LOCKPARENT) || !(cnp->cn_flags & ISLASTCN)) VOP_UNLOCK(ap->a_dvp); /* cache put*/ }else error=ENOENT; ntfs_free(walk.name); ntfs_free(item); return error;} /* later: readlink *//* TODO: abortop *//* TODO: lock *//* TODO: unlock */intntfs_islocked(ap) struct vop_islocked_args /* { struct vnode *a_vp; } */ *ap;{ /* FIXME: real locking */ return 0;}/* later: strategy */intntfs_reclaim(ap) struct vop_reclaim_args /* { struct vnode *a_vp; } */ *ap;{ struct ntfs_inode *ino=ap->a_vp->v_data; if(!ino) return EINVAL; LIST_REMOVE(ino,h_next); /* cache purge */ if(ino->i_number!=FILE_MFT) { ntfs_clear_inode(ino); ntfs_free(ino); } ap->a_vp->v_data=0; return 0;}int (**ntfs_vnodeop_p)();struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = { { &vop_default_desc, (vop_t*)vn_default_error }, { &vop_open_desc, ntfs_open }, { &vop_close_desc, ntfs_close }, { &vop_access_desc, ntfs_access }, { &vop_getattr_desc, ntfs_getattr }, { &vop_read_desc, ntfs_read }, { &vop_ioctl_desc, ntfs_ioctl }, { &vop_select_desc, ntfs_select }, { &vop_readdir_desc, ntfs_readdir }, { &vop_lookup_desc, ntfs_lookup }, { &vop_islocked_desc, ntfs_islocked }, { &vop_reclaim_desc, ntfs_reclaim }, { (struct vnodeop_desc *)NULL, (int (*)())NULL }};struct vnodeopv_desc ntfs_vnodeop_opv_desc = { &ntfs_vnodeop_p, ntfs_vnodeop_entries };VNODEOP_SET(ntfs_vnodeop_opv_desc);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -