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 void _ntfs_clear_inode(struct inode *inode) { ntfs_inode *ino; ntfs_volume *vol; lock_kernel(); ntfs_debug(DEBUG_OTHER, "_ntfs_clear_inode 0x%x\n", inode->i_ino); vol = NTFS_INO2VOL(inode); if (!vol) ntfs_error("_ntfs_clear_inode: vol = NTFS_INO2VOL(inode) is " "NULL.\n"); switch (inode->i_ino) { case FILE_Mft: if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) { ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); vol->mft_ino = ino; vol->ino_flags |= 1; goto unl_out; } break; case FILE_MftMirr: if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) { ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); vol->mftmirr = ino; vol->ino_flags |= 2; goto unl_out; } break; case FILE_BitMap: if (vol->bitmap && ((vol->ino_flags & 4) == 0)) { ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); vol->bitmap = ino; vol->ino_flags |= 4; goto unl_out; } break; default: /* Nothing. Just clear the inode and exit. */ } ntfs_clear_inode(&inode->u.ntfs_i); unl_out: unlock_kernel(); return; } /* Called when umounting a filesystem by do_umount() in fs/super.c. */ static void ntfs_put_super(struct super_block *sb) { ntfs_volume *vol; ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n"); vol = NTFS_SB2VOL(sb); ntfs_release_volume(vol); if (vol->nls_map) unload_nls(vol->nls_map); ntfs_debug(DEBUG_OTHER, "ntfs_put_super: done\n"); }
static int _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode) { int error; struct inode *r = 0; ntfs_volume *vol; ntfs_inode *ino; ntfs_attribute *si; ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n",d->d_name.name, dir->i_ino); error = ENAMETOOLONG; if (d->d_name.len > /* FIXME */255) goto out; error = EIO; r = get_empty_inode(); if (!r) goto out; vol = NTFS_INO2VOL(dir); #ifdef NTFS_IN_LINUX_KERNEL ino = NTFS_LINO2NINO(r); #else ino = ntfs_malloc(sizeof(ntfs_inode)); error = ENOMEM; if(!ino) goto out; r->u.generic_ip = ino; #endif error = ntfs_mkdir(NTFS_LINO2NINO(dir), d->d_name.name, d->d_name.len, ino); if(error) goto out; r->i_uid = vol->uid; r->i_gid = vol->gid; r->i_nlink = 1; r->i_sb = dir->i_sb; 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 a directory */ r->i_op = &ntfs_dir_inode_operations; r->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; #ifdef CONFIG_NTFS_RW r->i_mode|=S_IWUGO; #endif r->i_mode &= ~vol->umask; insert_inode_hash(r); d_instantiate(d, r); error = 0; out: ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", -error); return -error; }
static int ntfs_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); ino = NTFS_LINO2NINO(r); error = ntfs_alloc_file(NTFS_LINO2NINO(dir), ino, (char*)d->d_name.name, d->d_name.len); if (error) { ntfs_error("ntfs_alloc_file FAILED: error = %i", error); goto fail; } /* Not doing this one was causing a huge amount of corruption! Now the * bugger bytes the dust! (-8 (AIA) */ r->i_ino = ino->i_number; 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; r->i_fop = &ntfs_file_operations; 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: if (r) iput(r); return error; }
static int _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode) { int error; struct inode *r = 0; ntfs_volume *vol; ntfs_inode *ino; ntfs_attribute *si; ntfs_debug (DEBUG_DIR1, "mkdir %s in %x\n", d->d_name.name, dir->i_ino); error = -ENAMETOOLONG; if (d->d_name.len > /* FIXME: */ 255) goto out; error = -EIO; r = new_inode(dir->i_sb); if (!r) goto out; vol = NTFS_INO2VOL(dir); ino = NTFS_LINO2NINO(r); error = ntfs_mkdir(NTFS_LINO2NINO(dir), d->d_name.name, d->d_name.len, ino); if (error) goto out; /* Not doing this one was causing a huge amount of corruption! Now the * bugger bytes the dust! (-8 (AIA) */ r->i_ino = ino->i_number; r->i_uid = vol->uid; r->i_gid = vol->gid; 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 a directory. */ r->i_op = &ntfs_dir_inode_operations; r->i_fop = &ntfs_dir_operations; r->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; #ifdef CONFIG_NTFS_RW r->i_mode |= S_IWUGO; #endif r->i_mode &= ~vol->umask; insert_inode_hash(r); d_instantiate(d, r); error = 0; out: ntfs_debug (DEBUG_DIR1, "mkdir returns %d\n", error); 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; }
static void _ntfs_clear_inode(struct inode *inode) { ntfs_inode *ino; ntfs_volume *vol; lock_kernel(); ntfs_debug(DEBUG_OTHER, "_ntfs_clear_inode 0x%x\n", inode->i_ino); vol = NTFS_INO2VOL(inode); if (!vol) ntfs_error("_ntfs_clear_inode: vol = NTFS_INO2VOL(inode) is " "NULL.\n"); switch (inode->i_ino) { case FILE_Mft: if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) { ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); vol->mft_ino = ino; vol->ino_flags |= 1; goto unl_out; } break; case FILE_MftMirr: if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) { ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); vol->mftmirr = ino; vol->ino_flags |= 2; goto unl_out; } break; case FILE_BitMap: if (vol->bitmap && ((vol->ino_flags & 4) == 0)) { ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); vol->bitmap = ino; vol->ino_flags |= 4; goto unl_out; } break; /* Nothing. Just clear the inode and exit. */ } ntfs_clear_inode(&inode->u.ntfs_i); unl_out: unlock_kernel(); return; }
static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d) { struct inode *res = 0; char *item = 0; ntfs_iterate_s walk; int err; ntfs_debug(DEBUG_NAME1, __FUNCTION__ "(): Looking up %s in directory " "ino 0x%x.\n", d->d_name.name, (unsigned)dir->i_ino); walk.name = NULL; walk.namelen = 0; /* Convert to wide string. */ err = ntfs_decodeuni(NTFS_INO2VOL(dir), (char*)d->d_name.name, d->d_name.len, &walk.name, &walk.namelen); if (err) goto err_ret; item = ntfs_malloc(ITEM_SIZE); if (!item) { err = -ENOMEM; goto err_ret; } /* 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; err_ret: ntfs_free(walk.name); return ERR_PTR(err); }
/* 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; ntfs_inode *ino; ntfs_attribute *data; ntfs_attribute *si; vol = NTFS_INO2VOL(inode); inode->i_mode = 0; ntfs_debug(DEBUG_OTHER, "ntfs_read_inode 0x%lx\n", inode->i_ino); switch (inode->i_ino) { /* Those are loaded special files. */ case FILE_Mft: if (!vol->mft_ino || ((vol->ino_flags & 1) == 0)) goto sys_file_error; ntfs_memcpy(&inode->u.ntfs_i, vol->mft_ino, sizeof(ntfs_inode)); ino = vol->mft_ino; vol->mft_ino = &inode->u.ntfs_i; vol->ino_flags &= ~1; ntfs_free(ino); ino = vol->mft_ino; ntfs_debug(DEBUG_OTHER, "Opening $MFT!\n"); break; case FILE_MftMirr: if (!vol->mftmirr || ((vol->ino_flags & 2) == 0)) goto sys_file_error; ntfs_memcpy(&inode->u.ntfs_i, vol->mftmirr, sizeof(ntfs_inode)); ino = vol->mftmirr; vol->mftmirr = &inode->u.ntfs_i; vol->ino_flags &= ~2; ntfs_free(ino); ino = vol->mftmirr; ntfs_debug(DEBUG_OTHER, "Opening $MFTMirr!\n"); break; case FILE_BitMap: if (!vol->bitmap || ((vol->ino_flags & 4) == 0)) goto sys_file_error; ntfs_memcpy(&inode->u.ntfs_i, vol->bitmap, sizeof(ntfs_inode)); ino = vol->bitmap; vol->bitmap = &inode->u.ntfs_i; vol->ino_flags &= ~4; ntfs_free(ino); ino = vol->bitmap; ntfs_debug(DEBUG_OTHER, "Opening $Bitmap!\n"); break; case FILE_LogFile ... FILE_AttrDef: /* No need to log root directory accesses. */ case FILE_Boot ... FILE_UpCase: ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n", inode->i_ino); default: ino = &inode->u.ntfs_i; if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode), inode->i_ino)) { ntfs_debug(DEBUG_OTHER, "NTFS: Error loading inode " "0x%x\n", (unsigned int)inode->i_ino); return; } } /* 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, vol->at_data, NULL); if (!data) inode->i_size = 0; else inode->i_size = data->size; /* 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; 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, vol->at_index_root, "$I30")) { ntfs_attribute *at; at = ntfs_find_attr(ino, vol->at_index_allocation, "$I30"); inode->i_size = at ? at->size : 0; inode->i_op = &ntfs_dir_inode_operations; inode->i_fop = &ntfs_dir_operations; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; } else { inode->i_op = &ntfs_inode_operations; inode->i_fop = &ntfs_file_operations; inode->i_mode = S_IFREG | S_IRUGO; } #ifdef CONFIG_NTFS_RW if (!data || !(data->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED))) inode->i_mode |= S_IWUGO; #endif inode->i_mode &= ~vol->umask; return; sys_file_error: ntfs_error("Critical error. Tried to call ntfs_read_inode() before we " "have completed read_super() or VFS error.\n"); // FIXME: Should we panic() at this stage? }
/* * readdir returns '.', then '..', then the directory entries in sequence. * As the root directory contains an entry for itself, '.' is not emulated for * the root directory. */ static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir) { struct inode *dir = filp->f_dentry->d_inode; int err; struct ntfs_filldir cb; cb.ret_code = 0; cb.pl = filp->f_pos & 0xffff; cb.ph = (filp->f_pos >> 16) & 0x7fff; filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Entering for inode %lu, " "f_pos 0x%Lx, i_mode 0x%x, i_count %lu.\n", dir->i_ino, filp->f_pos, (unsigned int)dir->i_mode, atomic_read(&dir->i_count)); if (!cb.ph) { /* Start of directory. Emulate "." and "..". */ if (!cb.pl) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling " "filldir for . with len 1, f_pos 0x%Lx, " "inode %lu, DT_DIR.\n", filp->f_pos, dir->i_ino); cb.ret_code = filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR); if (cb.ret_code) goto done; cb.pl++; filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl; } if (cb.pl == (u32)1) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling " "filldir for .. with len 2, f_pos 0x%Lx, " "inode %lu, DT_DIR.\n", filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino); cb.ret_code = filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR); if (cb.ret_code) goto done; cb.pl++; filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl; } } else if (cb.ph >= 0x7fff) /* End of directory. */ goto done; cb.dir = dir; cb.filldir = filldir; cb.dirent = dirent; cb.type = NTFS_INO2VOL(dir)->ngt; do { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Looking for next " "file using ntfs_getdir_unsorted(), f_pos " "0x%Lx.\n", (loff_t)(cb.ph << 16) | cb.pl); err = ntfs_getdir_unsorted(NTFS_LINO2NINO(dir), &cb.ph, &cb.pl, ntfs_printcb, &cb); } while (!err && !cb.ret_code && cb.ph < 0x7fff); filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After ntfs_getdir_unsorted()" " calls, f_pos 0x%Lx.\n", filp->f_pos); if (!err) { done: #ifdef DEBUG if (!cb.ret_code) ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): EOD, f_pos " "0x%Lx, returning 0.\n", filp->f_pos); else ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): filldir " "returned %i, returning 0, f_pos " "0x%Lx.\n", cb.ret_code, filp->f_pos); #endif return 0; } ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Returning %i, f_pos 0x%Lx.\n", err, filp->f_pos); return err; }
static int ntfs_printcb(ntfs_u8 *entry, void *param) { unsigned long inum = NTFS_GETU64(entry) & 0xffffffffffff; struct ntfs_filldir *nf = param; u32 flags = NTFS_GETU32(entry + 0x48); char show_sys_files = 0; u8 name_len = NTFS_GETU8(entry + 0x50); u8 name_type = NTFS_GETU8(entry + 0x51); int err; unsigned file_type; switch (nf->type) { case ngt_dos: /* Don't display long names. */ if (!(name_type & 2)) return 0; break; case ngt_nt: /* Don't display short-only names. */ if ((name_type & 3) == 2) return 0; break; case ngt_posix: break; case ngt_full: show_sys_files = 1; break; default: BUG(); } err = ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52), name_len, &nf->name, &nf->namelen); if (err) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping " "unrepresentable file.\n"); err = 0; goto err_ret; } if (!show_sys_files && inum < 0x10UL) { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping system " "file (%s).\n", nf->name); err = 0; goto err_ret; } /* Do not return ".", as this is faked. */ if (nf->namelen == 1 && nf->name[0] == '.') { ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping \".\"\n"); err = 0; goto err_ret; } nf->name[nf->namelen] = 0; if (flags & 0x10000000) /* FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT */ file_type = DT_DIR; else file_type = DT_REG; ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Calling filldir for %s with " "len %i, f_pos 0x%Lx, inode %lu, %s.\n", nf->name, nf->namelen, (loff_t)(nf->ph << 16) | nf->pl, inum, file_type == DT_DIR ? "DT_DIR" : "DT_REG"); /* * Userspace side of filldir expects an off_t rather than an loff_t. * And it also doesn't like the most significant bit being set as it * then considers the value to be negative. Thus this implementation * limits the number of index records to 32766, which should be plenty. */ err = nf->filldir(nf->dirent, nf->name, nf->namelen, (loff_t)(nf->ph << 16) | nf->pl, inum, file_type); if (err) nf->ret_code = err; err_ret: nf->namelen = 0; ntfs_free(nf->name); nf->name = NULL; return err; }
/* 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_mode=0; ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n",(unsigned)inode->i_ino); switch(inode->i_ino) { /* those are loaded special files */ case FILE_MFT: ntfs_error("Trying to open MFT\n");return; default: #ifdef NTFS_IN_LINUX_KERNEL ino=&inode->u.ntfs_i; #else /* FIXME: check for ntfs_malloc failure */ ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); inode->u.generic_ip=ino; #endif if(!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),inode->i_ino)) { ntfs_debug(DEBUG_OTHER, "NTFS:Error loading inode %x\n", (unsigned int)inode->i_ino); return; } } /* 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,vol->at_data,NULL); if(!data) { inode->i_size=0; can_mmap=0; } else { inode->i_size=data->size; /* FIXME: once ntfs_get_block is implemented, uncomment the * next line and remove the can_mmap = 0; */ /* can_mmap=!data->resident && !data->compressed;*/ can_mmap = 0; } /* 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; 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,vol->at_index_root,"$I30")) { ntfs_attribute *at; at = ntfs_find_attr (ino, vol->at_index_allocation, "$I30"); inode->i_size = at ? at->size : 0; inode->i_op=&ntfs_dir_inode_operations; inode->i_fop=&ntfs_dir_operations; inode->i_mode=S_IFDIR|S_IRUGO|S_IXUGO; } else { /* As long as ntfs_get_block() is just a call to BUG() do not * define any [bm]map ops or we get the BUG() whenever someone * runs mc or mpg123 on an ntfs partition! * FIXME: Uncomment the below code when ntfs_get_block is * implemented. */ /* if (can_mmap) { inode->i_op = &ntfs_inode_operations; inode->i_fop = &ntfs_file_operations; inode->i_mapping->a_ops = &ntfs_aops; inode->u.ntfs_i.mmu_private = inode->i_size; } else */ { inode->i_op=&ntfs_inode_operations_nobmap; inode->i_fop=&ntfs_file_operations_nommap; } inode->i_mode=S_IFREG|S_IRUGO; } #ifdef CONFIG_NTFS_RW if(!data || !data->compressed) inode->i_mode|=S_IWUGO; #endif inode->i_mode &= ~vol->umask; }
static int ntfs_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 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; }
/* 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; ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n",(unsigned)inode->i_ino); switch(inode->i_ino) { /* those are loaded special files */ case FILE_MFT: ntfs_error("Trying to open MFT\n");return; default: #ifdef NTFS_IN_LINUX_KERNEL ino=&inode->u.ntfs_i; #else /* FIXME: check for ntfs_malloc failure */ ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); inode->u.generic_ip=ino; #endif if(!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),inode->i_ino)) { ntfs_debug(DEBUG_OTHER, "NTFS:Error loading inode %x\n", (unsigned int)inode->i_ino); return; } } /* 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,vol->at_data,NULL); if(!data) { inode->i_size=0; can_mmap=0; } else { inode->i_size=data->size; can_mmap=!data->resident && !data->compressed; } /* 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; 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,vol->at_index_root,"$I30")) { ntfs_attribute *at; at = ntfs_find_attr (ino, vol->at_index_allocation, "$I30"); inode->i_size = at ? at->size : 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; } #ifdef CONFIG_NTFS_RW if(!data || !data->compressed) inode->i_mode|=S_IWUGO; #endif inode->i_mode &= ~vol->umask; }