inode.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,057 行 · 第 1/5 页
C
2,057 行
ntfs_error(vi->i_sb, "Failed with error code %i while reading index " "inode (mft_no 0x%lx, name_len %i.", -err, vi->i_ino, ni->name_len); make_bad_inode(vi); return err;}/** * ntfs_read_inode_mount - special read_inode for mount time use only * @vi: inode to read * * Read inode FILE_MFT at mount time, only called with super_block lock * held from within the read_super() code path. * * This function exists because when it is called the page cache for $MFT/$DATA * is not initialized and hence we cannot get at the contents of mft records * by calling map_mft_record*(). * * Further it needs to cope with the circular references problem, i.e. cannot * load any attributes other than $ATTRIBUTE_LIST until $DATA is loaded, because * we do not know where the other extent mft records are yet and again, because * we cannot call map_mft_record*() yet. Obviously this applies only when an * attribute list is actually present in $MFT inode. * * We solve these problems by starting with the $DATA attribute before anything * else and iterating using ntfs_attr_lookup($DATA) over all extents. As each * extent is found, we decompress_mapping_pairs() including the implied * ntfs_merge_runlists(). Each step of the iteration necessarily provides * sufficient information for the next step to complete. * * This should work but there are two possible pit falls (see inline comments * below), but only time will tell if they are real pits or just smoke... */int ntfs_read_inode_mount(struct inode *vi){ VCN next_vcn, last_vcn, highest_vcn; s64 block; struct super_block *sb = vi->i_sb; ntfs_volume *vol = NTFS_SB(sb); struct buffer_head *bh; ntfs_inode *ni; MFT_RECORD *m = NULL; ATTR_RECORD *attr; ntfs_attr_search_ctx *ctx; unsigned int i, nr_blocks; int err; ntfs_debug("Entering."); /* Initialize the ntfs specific part of @vi. */ ntfs_init_big_inode(vi); ni = NTFS_I(vi); /* Setup the data attribute. It is special as it is mst protected. */ NInoSetNonResident(ni); NInoSetMstProtected(ni); ni->type = AT_DATA; ni->name = NULL; ni->name_len = 0; /* * This sets up our little cheat allowing us to reuse the async read io * completion handler for directories. */ ni->itype.index.block_size = vol->mft_record_size; ni->itype.index.block_size_bits = vol->mft_record_size_bits; /* Very important! Needed to be able to call map_mft_record*(). */ vol->mft_ino = vi; /* Allocate enough memory to read the first mft record. */ if (vol->mft_record_size > 64 * 1024) { ntfs_error(sb, "Unsupported mft record size %i (max 64kiB).", vol->mft_record_size); goto err_out; } i = vol->mft_record_size; if (i < sb->s_blocksize) i = sb->s_blocksize; m = (MFT_RECORD*)ntfs_malloc_nofs(i); if (!m) { ntfs_error(sb, "Failed to allocate buffer for $MFT record 0."); goto err_out; } /* Determine the first block of the $MFT/$DATA attribute. */ block = vol->mft_lcn << vol->cluster_size_bits >> sb->s_blocksize_bits; nr_blocks = vol->mft_record_size >> sb->s_blocksize_bits; if (!nr_blocks) nr_blocks = 1; /* Load $MFT/$DATA's first mft record. */ for (i = 0; i < nr_blocks; i++) { bh = sb_bread(sb, block++); if (!bh) { ntfs_error(sb, "Device read failed."); goto err_out; } memcpy((char*)m + (i << sb->s_blocksize_bits), bh->b_data, sb->s_blocksize); brelse(bh); } /* Apply the mst fixups. */ if (post_read_mst_fixup((NTFS_RECORD*)m, vol->mft_record_size)) { /* FIXME: Try to use the $MFTMirr now. */ ntfs_error(sb, "MST fixup failed. $MFT is corrupt."); goto err_out; } /* Need this to sanity check attribute list references to $MFT. */ vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number); /* Provides readpage() and sync_page() for map_mft_record(). */ vi->i_mapping->a_ops = &ntfs_mft_aops; ctx = ntfs_attr_get_search_ctx(ni, m); if (!ctx) { err = -ENOMEM; goto err_out; } /* Find the attribute list attribute if present. */ err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx); if (err) { if (unlikely(err != -ENOENT)) { ntfs_error(sb, "Failed to lookup attribute list " "attribute. You should run chkdsk."); goto put_err_out; } } else /* if (!err) */ { ATTR_LIST_ENTRY *al_entry, *next_al_entry; u8 *al_end; ntfs_debug("Attribute list attribute found in $MFT."); NInoSetAttrList(ni); if (ctx->attr->flags & ATTR_IS_ENCRYPTED || ctx->attr->flags & ATTR_COMPRESSION_MASK || ctx->attr->flags & ATTR_IS_SPARSE) { ntfs_error(sb, "Attribute list attribute is " "compressed/encrypted/sparse. Not " "allowed. $MFT is corrupt. You should " "run chkdsk."); goto put_err_out; } /* Now allocate memory for the attribute list. */ ni->attr_list_size = (u32)ntfs_attr_size(ctx->attr); ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); if (!ni->attr_list) { ntfs_error(sb, "Not enough memory to allocate buffer " "for attribute list."); goto put_err_out; } if (ctx->attr->non_resident) { NInoSetAttrListNonResident(ni); if (ctx->attr->data.non_resident.lowest_vcn) { ntfs_error(sb, "Attribute list has non zero " "lowest_vcn. $MFT is corrupt. " "You should run chkdsk."); goto put_err_out; } /* Setup the runlist. */ ni->attr_list_rl.rl = decompress_mapping_pairs(vol, ctx->attr, NULL); if (IS_ERR(ni->attr_list_rl.rl)) { err = PTR_ERR(ni->attr_list_rl.rl); ni->attr_list_rl.rl = NULL; ntfs_error(sb, "Mapping pairs decompression " "failed with error code %i.", -err); goto put_err_out; } /* Now load the attribute list. */ if ((err = load_attribute_list(vol, &ni->attr_list_rl, ni->attr_list, ni->attr_list_size, sle64_to_cpu(ctx->attr->data. non_resident.initialized_size)))) { ntfs_error(sb, "Failed to load attribute list " "attribute with error code %i.", -err); goto put_err_out; } } else /* if (!ctx.attr->non_resident) */ { if ((u8*)ctx->attr + le16_to_cpu( ctx->attr->data.resident.value_offset) + le32_to_cpu( ctx->attr->data.resident.value_length) > (u8*)ctx->mrec + vol->mft_record_size) { ntfs_error(sb, "Corrupt attribute list " "attribute."); goto put_err_out; } /* Now copy the attribute list. */ memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu( ctx->attr->data.resident.value_offset), le32_to_cpu( ctx->attr->data.resident.value_length)); } /* The attribute list is now setup in memory. */ /* * FIXME: I don't know if this case is actually possible. * According to logic it is not possible but I have seen too * many weird things in MS software to rely on logic... Thus we * perform a manual search and make sure the first $MFT/$DATA * extent is in the base inode. If it is not we abort with an * error and if we ever see a report of this error we will need * to do some magic in order to have the necessary mft record * loaded and in the right place in the page cache. But * hopefully logic will prevail and this never happens... */ al_entry = (ATTR_LIST_ENTRY*)ni->attr_list; al_end = (u8*)al_entry + ni->attr_list_size; for (;; al_entry = next_al_entry) { /* Out of bounds check. */ if ((u8*)al_entry < ni->attr_list || (u8*)al_entry > al_end) goto em_put_err_out; /* Catch the end of the attribute list. */ if ((u8*)al_entry == al_end) goto em_put_err_out; if (!al_entry->length) goto em_put_err_out; if ((u8*)al_entry + 6 > al_end || (u8*)al_entry + le16_to_cpu(al_entry->length) > al_end) goto em_put_err_out; next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + le16_to_cpu(al_entry->length)); if (le32_to_cpu(al_entry->type) > const_le32_to_cpu(AT_DATA)) goto em_put_err_out; if (AT_DATA != al_entry->type) continue; /* We want an unnamed attribute. */ if (al_entry->name_length) goto em_put_err_out; /* Want the first entry, i.e. lowest_vcn == 0. */ if (al_entry->lowest_vcn) goto em_put_err_out; /* First entry has to be in the base mft record. */ if (MREF_LE(al_entry->mft_reference) != vi->i_ino) { /* MFT references do not match, logic fails. */ ntfs_error(sb, "BUG: The first $DATA extent " "of $MFT is not in the base " "mft record. Please report " "you saw this message to " "linux-ntfs-dev@lists." "sourceforge.net"); goto put_err_out; } else { /* Sequence numbers must match. */ if (MSEQNO_LE(al_entry->mft_reference) != ni->seq_no) goto em_put_err_out; /* Got it. All is ok. We can stop now. */ break; } } } ntfs_attr_reinit_search_ctx(ctx); /* Now load all attribute extents. */ attr = NULL; next_vcn = last_vcn = highest_vcn = 0; while (!(err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, next_vcn, NULL, 0, ctx))) { runlist_element *nrl; /* Cache the current attribute. */ attr = ctx->attr; /* $MFT must be non-resident. */ if (!attr->non_resident) { ntfs_error(sb, "$MFT must be non-resident but a " "resident extent was found. $MFT is " "corrupt. Run chkdsk."); goto put_err_out; } /* $MFT must be uncompressed and unencrypted. */ if (attr->flags & ATTR_COMPRESSION_MASK || attr->flags & ATTR_IS_ENCRYPTED || attr->flags & ATTR_IS_SPARSE) { ntfs_error(sb, "$MFT must be uncompressed, " "non-sparse, and unencrypted but a " "compressed/sparse/encrypted extent " "was found. $MFT is corrupt. Run " "chkdsk."); goto put_err_out; } /* * Decompress the mapping pairs array of this extent and merge * the result into the existing runlist. No need for locking * as we have exclusive access to the inode at this time and we * are a mount in progress task, too. */ nrl = decompress_mapping_pairs(vol, attr, ni->runlist.rl); if (IS_ERR(nrl)) { ntfs_error(sb, "decompress_mapping_pairs() failed with " "error code %ld. $MFT is corrupt.", PTR_ERR(nrl)); goto put_err_out; } ni->runlist.rl = nrl; /* Are we in the first extent? */ if (!next_vcn) { if (attr->data.non_resident.lowest_vcn) { ntfs_error(sb, "First extent of $DATA " "attribute has non zero " "lowest_vcn. $MFT is corrupt. " "You should run chkdsk."); goto put_err_out; } /* Get the last vcn in the $DATA attribute. */ last_vcn = sle64_to_cpu( attr->data.non_resident.allocated_size) >> vol->cluster_size_bits; /* Fill in the inode size. */ vi->i_size = sle64_to_cpu( attr->data.non_resident.data_size); ni->initialized_size = sle64_to_cpu(attr->data. non_resident.initialized_size); ni->allocated_size = sle64_to_cpu( attr->data.non_resident.allocated_size); /* * Verify the number of mft records does not exceed * 2^32 - 1. */ if ((vi->i_size >> vol->mft_record_size_bits) >= (1ULL << 32)) { ntfs_error(sb, "$MFT is too big! Aborting."); goto put_err_out; } /* * We have got the first extent of the runlist for * $MFT which means it is now relatively safe to call * the normal ntfs_read_inode() function. * Complete reading the inode, this will actually * re-read the mft record for $MFT, this time entering * it into the page cache with which we complete the * kick start of the volume. It should be safe to do * this now as the first extent of $MFT/$DATA is * already known and we would hope that we don't need * further extents in order to find the other * attributes belonging to $MFT. Only time will tell if * this is really the case. If not we will have to play * magic at this point, possibly duplicating a lot of * ntfs_read_inode() at this point. We will need to * ensure we do enough of its work to be able to call * ntfs_read_inode() on extents of $MFT/$DATA. But lets * hope this never happens... */ ntfs_read_locked_inode(vi); if (is_bad_inode(vi)) { ntfs_error(sb, "ntfs_read_inode() of $MFT " "failed. BUG or corrupt $MFT. " "Run chkdsk and if no errors " "are found, please report you " "saw this message to " "linux-ntfs-dev@lists." "sourceforge.net"); ntfs_attr_put_search_ctx(ctx); /* Revert to the safe super operations. */ ntfs_free(m); return -1; } /* * Re-initialize some specifics about $MFT's inode as * ntfs_read_inode() will have set up the default ones. */ /* Set uid and gid to root. */ vi->i_uid = vi->i_gid = 0; /* Regular file. No access for anyone. */ vi->i_mode = S_IFREG; /* No VFS initiated operations allowed for $MFT. */ vi->i_op = &ntfs_empty_inode_ops; vi->i_fop = &ntfs_empty_file_ops; /* Put back our special address space operations. */ vi->i_mapping->a_ops = &ntfs_mft_aops; } /* Get the lowest vcn for the next extent. */ highest_vcn = sle64_to_cpu(attr->data.non_resident.highest_vcn); next_vcn = highest_vcn + 1; /* Only one extent or error, which we catch below. */ if (next_vcn <= 0) break; /* Avoid endless loops due to corruption. */ if (next_vcn < sle64_to_cpu( attr->data.non_resident.lowest_vcn)) { ntfs_error(sb, "$MFT has corrupt attribute list " "attribute. Run chkdsk."); goto put_err_out; } } if (err != -ENOENT) { ntfs_error(sb, "Failed to lookup $MFT/$DATA attribute extent. " "$MFT is corrupt. Run chkdsk."); goto put_err_out; } if (!attr) { ntfs_error(sb, "$MFT/$DATA attribute not found. $MFT is " "corrupt. Run chkdsk."); goto put_err_out; } if (highest_vcn
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?