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 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; }
/* 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? }
/* Called to mount a filesystem by read_super() in fs/super.c. * Return a super block, the main structure of a filesystem. * * NOTE : Don't store a pointer to an option, as the page containing the * options is freed after ntfs_read_super() returns. * * NOTE : A context switch can happen in kernel code only if the code blocks * (= calls schedule() in kernel/sched.c). */ struct super_block *ntfs_read_super(struct super_block *sb, void *options, int silent) { ntfs_volume *vol; struct buffer_head *bh; int i, to_read, blocksize; ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n"); vol = NTFS_SB2VOL(sb); init_ntfs_super_block(vol); if (!parse_options(vol, (char*)options)) goto ntfs_read_super_vol; blocksize = get_hardsect_size(sb->s_dev); if (blocksize < 512) blocksize = 512; if (set_blocksize(sb->s_dev, blocksize) < 0) { ntfs_error("Unable to set blocksize %d.\n", blocksize); goto ntfs_read_super_vol; } sb->s_blocksize = blocksize; /* Read the super block (boot block). */ if (!(bh = sb_bread(sb, 0))) { ntfs_error("Reading super block failed\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Done reading boot block\n"); /* Check for valid 'NTFS' boot sector. */ if (!is_boot_sector_ntfs(bh->b_data)) { ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n"); bforget(bh); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Going to init volume\n"); if (ntfs_init_volume(vol, bh->b_data) < 0) { ntfs_debug(DEBUG_OTHER, "Init volume failed.\n"); bforget(bh); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%lx\n", vol->mft_lcn); brelse(bh); NTFS_SB(vol) = sb; if (vol->cluster_size > PAGE_SIZE) { ntfs_error("Partition cluster size is not supported yet (it " "is > max kernel blocksize).\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); /* Inform the kernel that a device block is a NTFS cluster. */ sb->s_blocksize = vol->cluster_size; sb->s_blocksize_bits = vol->cluster_size_bits; if (blocksize != vol->cluster_size && set_blocksize(sb->s_dev, sb->s_blocksize) < 0) { ntfs_error("Cluster size too small for device.\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "set_blocksize\n"); /* Allocate an MFT record (MFT record can be smaller than a cluster). */ i = vol->cluster_size; if (i < vol->mft_record_size) i = vol->mft_record_size; if (!(vol->mft = ntfs_malloc(i))) goto ntfs_read_super_unl; /* Read at least the MFT record for $Mft. */ to_read = vol->mft_clusters_per_record; if (to_read < 1) to_read = 1; for (i = 0; i < to_read; i++) { if (!(bh = sb_bread(sb, vol->mft_lcn + i))) { ntfs_error("Could not read $Mft record 0\n"); goto ntfs_read_super_mft; } ntfs_memcpy(vol->mft + ((__s64)i << vol->cluster_size_bits), bh->b_data, vol->cluster_size); brelse(bh); ntfs_debug(DEBUG_OTHER, "Read cluster 0x%x\n", vol->mft_lcn + i); } /* Check and fixup this MFT record */ if (!ntfs_check_mft_record(vol, vol->mft)){ ntfs_error("Invalid $Mft record 0\n"); goto ntfs_read_super_mft; } /* Inform the kernel about which super operations are available. */ sb->s_op = &ntfs_super_operations; sb->s_magic = NTFS_SUPER_MAGIC; sb->s_maxbytes = ~0ULL >> 1; ntfs_debug(DEBUG_OTHER, "Reading special files\n"); if (ntfs_load_special_files(vol)) { ntfs_error("Error loading special files\n"); goto ntfs_read_super_mft; } ntfs_debug(DEBUG_OTHER, "Getting RootDir\n"); /* Get the root directory. */ if (!(sb->s_root = d_alloc_root(iget(sb, FILE_root)))) { ntfs_error("Could not get root dir inode\n"); goto ntfs_read_super_mft; } ntfs_read_super_ret: ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return sb; ntfs_read_super_mft: ntfs_free(vol->mft); ntfs_read_super_unl: ntfs_read_super_vol: sb = NULL; goto ntfs_read_super_ret; }
/* Called to mount a filesystem by read_super() in fs/super.c * Return a super block, the main structure of a filesystem * * NOTE : Don't store a pointer to an option, as the page containing the * options is freed after ntfs_read_super() returns. * * NOTE : A context switch can happen in kernel code only if the code blocks * (= calls schedule() in kernel/sched.c). */ struct super_block * ntfs_read_super(struct super_block *sb, void *options, int silent) { ntfs_volume *vol; struct buffer_head *bh; int i; ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n"); #ifdef NTFS_IN_LINUX_KERNEL vol = NTFS_SB2VOL(sb); #else if(!(vol = ntfs_malloc(sizeof(ntfs_volume)))) goto ntfs_read_super_dec; NTFS_SB2VOL(sb)=vol; #endif if(!parse_options(vol,(char*)options)) goto ntfs_read_super_vol; #if 0 /* Set to read only, user option might reset it */ sb->s_flags |= MS_RDONLY; #endif /* Assume a 512 bytes block device for now */ set_blocksize(sb->s_dev, 512); /* Read the super block (boot block) */ if(!(bh=bread(sb->s_dev,0,512))) { ntfs_error("Reading super block failed\n"); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Done reading boot block\n"); /* Check for 'NTFS' magic number */ if(!IS_NTFS_VOLUME(bh->b_data)){ ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n"); brelse(bh); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Going to init volume\n"); ntfs_init_volume(vol,bh->b_data); ntfs_debug(DEBUG_OTHER, "MFT record at cluster 0x%X\n",vol->mft_cluster); brelse(bh); NTFS_SB(vol)=sb; ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); /* Inform the kernel that a device block is a NTFS cluster */ sb->s_blocksize=vol->clustersize; for(i=sb->s_blocksize,sb->s_blocksize_bits=0;i != 1;i>>=1) sb->s_blocksize_bits++; set_blocksize(sb->s_dev,sb->s_blocksize); ntfs_debug(DEBUG_OTHER, "set_blocksize\n"); /* Allocate a MFT record (MFT record can be smaller than a cluster) */ if(!(vol->mft=ntfs_malloc(max(vol->mft_recordsize,vol->clustersize)))) goto ntfs_read_super_unl; /* Read at least the MFT record for $MFT */ for(i=0;i<max(vol->mft_clusters_per_record,1);i++){ if(!(bh=bread(sb->s_dev,vol->mft_cluster+i,vol->clustersize))) { ntfs_error("Could not read MFT record 0\n"); goto ntfs_read_super_mft; } ntfs_memcpy(vol->mft+i*vol->clustersize,bh->b_data,vol->clustersize); brelse(bh); ntfs_debug(DEBUG_OTHER, "Read cluster %x\n",vol->mft_cluster+i); } /* Check and fixup this MFT record */ if(!ntfs_check_mft_record(vol,vol->mft)){ ntfs_error("Invalid MFT record 0\n"); goto ntfs_read_super_mft; } /* Inform the kernel about which super operations are available */ sb->s_op = &ntfs_super_operations; sb->s_magic = NTFS_SUPER_MAGIC; ntfs_debug(DEBUG_OTHER, "Reading special files\n"); if(ntfs_load_special_files(vol)){ ntfs_error("Error loading special files\n"); goto ntfs_read_super_mft; } ntfs_debug(DEBUG_OTHER, "Getting RootDir\n"); /* Get the root directory */ if(!(sb->s_root=d_alloc_root(iget(sb,FILE_ROOT)))){ ntfs_error("Could not get root dir inode\n"); goto ntfs_read_super_mft; } ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return sb; ntfs_read_super_mft: ntfs_free(vol->mft); ntfs_read_super_unl: ntfs_read_super_vol: #ifndef NTFS_IN_LINUX_KERNEL ntfs_free(vol); ntfs_read_super_dec: #endif ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return NULL; }