⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				"compressed.");		goto unm_err_out;	}	if (a->data.non_resident.lowest_vcn) {		ntfs_error(vi->i_sb, "First extent of $INDEX_ALLOCATION "				"attribute has non zero lowest_vcn.");		goto unm_err_out;	}	vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);	ni->initialized_size = sle64_to_cpu(			a->data.non_resident.initialized_size);	ni->allocated_size = sle64_to_cpu(a->data.non_resident.allocated_size);	/*	 * We are done with the mft record, so we release it.  Otherwise	 * we would deadlock in ntfs_attr_iget().	 */	ntfs_attr_put_search_ctx(ctx);	unmap_mft_record(base_ni);	m = NULL;	ctx = NULL;	/* Get the index bitmap attribute inode. */	bvi = ntfs_attr_iget(base_vi, AT_BITMAP, ni->name, ni->name_len);	if (IS_ERR(bvi)) {		ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");		err = PTR_ERR(bvi);		goto unm_err_out;	}	bni = NTFS_I(bvi);	if (NInoCompressed(bni) || NInoEncrypted(bni) ||			NInoSparse(bni)) {		ntfs_error(vi->i_sb, "$BITMAP attribute is compressed and/or "				"encrypted and/or sparse.");		goto iput_unm_err_out;	}	/* Consistency check bitmap size vs. index allocation size. */	bvi_size = i_size_read(bvi);	if ((bvi_size << 3) < (vi->i_size >> ni->itype.index.block_size_bits)) {		ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) for "				"index allocation (0x%llx).", bvi_size << 3,				vi->i_size);		goto iput_unm_err_out;	}	iput(bvi);skip_large_index_stuff:	/* Setup the operations for this index inode. */	vi->i_op = NULL;	vi->i_fop = NULL;	vi->i_mapping->a_ops = &ntfs_mst_aops;	vi->i_blocks = ni->allocated_size >> 9;	/*	 * Make sure the base inode doesn't go away and attach it to the	 * index inode.	 */	igrab(base_vi);	ni->ext.base_ntfs_ino = base_ni;	ni->nr_extents = -1;	ntfs_debug("Done.");	return 0;iput_unm_err_out:	iput(bvi);unm_err_out:	if (!err)		err = -EIO;	if (ctx)		ntfs_attr_put_search_ctx(ctx);	if (m)		unmap_mft_record(base_ni);err_out:	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);	if (err != -EOPNOTSUPP && err != -ENOMEM)		NVolSetErrors(vol);	return err;}/* * The MFT inode has special locking, so teach the lock validator * about this by splitting off the locking rules of the MFT from * the locking rules of other inodes. The MFT inode can never be * accessed from the VFS side (or even internally), only by the * map_mft functions. */static struct lock_class_key mft_ni_runlist_lock_key, mft_ni_mrec_lock_key;/** * 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 ntfs_mapping_pairs_decompress() including the implied * ntfs_runlists_merge().  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 *a;	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);	NInoSetSparseDisabled(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_mst_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;		static const char *es = "  Not allowed.  $MFT is corrupt.  "				"You should run chkdsk.";		ntfs_debug("Attribute list attribute found in $MFT.");		NInoSetAttrList(ni);		a = ctx->attr;		if (a->flags & ATTR_COMPRESSION_MASK) {			ntfs_error(sb, "Attribute list attribute is "					"compressed.%s", es);			goto put_err_out;		}		if (a->flags & ATTR_IS_ENCRYPTED ||				a->flags & ATTR_IS_SPARSE) {			if (a->non_resident) {				ntfs_error(sb, "Non-resident attribute list "						"attribute is encrypted/"						"sparse.%s", es);				goto put_err_out;			}			ntfs_warning(sb, "Resident attribute list attribute "					"in $MFT system file is marked "					"encrypted/sparse which is not true.  "					"However, Windows allows this and "					"chkdsk does not detect or correct it "					"so we will just ignore the invalid "					"flags and pretend they are not set.");		}		/* Now allocate memory for the attribute list. */		ni->attr_list_size = (u32)ntfs_attr_size(a);		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 (a->non_resident) {			NInoSetAttrListNonResident(ni);			if (a->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 = ntfs_mapping_pairs_decompress(vol,					a, 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(a->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*)a + le16_to_cpu(					a->data.resident.value_offset) +					le32_to_cpu(					a->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*)a + le16_to_cpu(					a->data.resident.value_offset),					le32_to_cpu(					a->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. */	a = 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. */		a = ctx->attr;		/* $MFT must be non-resident. */		if (!a->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 (a->flags & ATTR_COMPRESSION_MASK ||				a->flags & ATTR_IS_ENCRYPTED ||				a->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 = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl);		if (IS_ERR(nrl)) {			ntfs_error(sb, "ntfs_mapping_pairs_decompress() "					"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 (a->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(		

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -