Beispiel #1
0
static int ntfs_ir_reparent(ntfs_index_context *icx)
{
	ntfs_attr_search_ctx *ctx = NULL;
	INDEX_ROOT *ir;
	INDEX_ENTRY *ie;
	INDEX_BLOCK *ib = NULL;
	VCN new_ib_vcn;
	int ix_root_size;
	int ret = STATUS_ERROR;

	ntfs_log_trace("Entering\n");
	
	ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
	if (!ir)
		goto out;
	
	if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX)
		if (ntfs_ia_add(icx))
			goto out;
	
	new_ib_vcn = ntfs_ibm_get_free(icx);
	if (new_ib_vcn == -1)
		goto out;
		
	ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
	if (!ir)
		goto clear_bmp;
	
	ib = ntfs_ir_to_ib(ir, new_ib_vcn);
	if (ib == NULL) {
		ntfs_log_perror("Failed to move index root to index block");
		goto clear_bmp;
	}
		
	if (ntfs_ib_write(icx, ib))
		goto clear_bmp;
	
retry :
	ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
	if (!ir)
		goto clear_bmp;
	
	ntfs_ir_nill(ir);
	
	ie = ntfs_ie_get_first(&ir->index);
	ie->ie_flags |= INDEX_ENTRY_NODE;
	ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN));
	
	ir->index.ih_flags = LARGE_INDEX;
	ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset)
					     + le16_to_cpu(ie->length));
	ir->index.allocated_size = ir->index.index_length;
	ix_root_size = sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER)
			+ le32_to_cpu(ir->index.allocated_size);
	if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
					ix_root_size)) {
			/*
			 * When there is no space to build a non-resident
			 * index, we may have to move the root to an extent
			 */
		if ((errno == ENOSPC)
		    && !ctx->al_entry
		    && !ntfs_inode_add_attrlist(icx->ni)) {
			ntfs_attr_put_search_ctx(ctx);
			ctx = (ntfs_attr_search_ctx*)NULL;
			ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len,
							&ctx);
			if (ir
			    && !ntfs_attr_record_move_away(ctx, ix_root_size
				    - le32_to_cpu(ctx->attr->value_length))) {
				ntfs_attr_put_search_ctx(ctx);
				ctx = (ntfs_attr_search_ctx*)NULL;
				goto retry;
			}
		}
		/* FIXME: revert index root */
		goto clear_bmp;
	}
	/*
	 *  FIXME: do it earlier if we have enough space in IR (should always),
	 *  so in error case we wouldn't lose the IB.
	 */
	ntfs_ie_set_vcn(ie, new_ib_vcn);
	
	ret = STATUS_OK;
err_out:
	free(ib);
	ntfs_attr_put_search_ctx(ctx);
out:
	return ret;
clear_bmp:
	ntfs_ibm_clear(icx, new_ib_vcn);
	goto err_out;
}
Beispiel #2
0
/**
 * ntfs_inode_free_space - free space in the MFT record of an inode
 * @ni:		ntfs inode in which MFT record needs more free space
 * @size:	amount of space needed to free
 *
 * Return 0 on success or -1 on error with errno set to the error code.
 */
int ntfs_inode_free_space(ntfs_inode *ni, int size)
{
	ntfs_attr_search_ctx *ctx;
	int freed;

	if (!ni || size < 0) {
		errno = EINVAL;
		ntfs_log_perror("%s: ni=%p size=%d", __FUNCTION__, ni, size);
		return -1;
	}

	ntfs_log_trace("Entering for inode %lld, size %d\n",
		       (unsigned long long)ni->mft_no, size);

	freed = (le32_to_cpu(ni->mrec->bytes_allocated) -
				le32_to_cpu(ni->mrec->bytes_in_use));

	if (size <= freed)
		return 0;

	ctx = ntfs_attr_get_search_ctx(ni, NULL);
	if (!ctx)
		return -1;
	/*
	 * $STANDARD_INFORMATION and $ATTRIBUTE_LIST must stay in the base MFT
	 * record, so position search context on the first attribute after them.
	 */
	if (ntfs_attr_position(AT_FILE_NAME, ctx))
		goto put_err_out;

	while (1) {
		int record_size;
		/*
		 * Check whether attribute is from different MFT record. If so,
		 * find next, because we don't need such.
		 */
		while (ctx->ntfs_ino->mft_no != ni->mft_no) {
retry:
			if (ntfs_attr_position(AT_UNUSED, ctx))
				goto put_err_out;
		}

		if (ntfs_inode_base(ctx->ntfs_ino)->mft_no == FILE_MFT &&
		    ctx->attr->type == AT_DATA)
			goto retry;

		if (ctx->attr->type == AT_INDEX_ROOT)
			goto retry;

		record_size = le32_to_cpu(ctx->attr->length);

		if (ntfs_attr_record_move_away(ctx, 0)) {
			ntfs_log_perror("Failed to move out attribute #2");
			break;
		}
		freed += record_size;

		/* Check whether we are done. */
		if (size <= freed) {
			ntfs_attr_put_search_ctx(ctx);
			return 0;
		}
		/*
		 * Reposition to first attribute after $STANDARD_INFORMATION
		 * and $ATTRIBUTE_LIST instead of simply skipping this attribute
		 * because in the case when we have got only in-memory attribute
		 * list then ntfs_attr_lookup will fail when it tries to find
		 * $ATTRIBUTE_LIST.
		 */
		ntfs_attr_reinit_search_ctx(ctx);
		if (ntfs_attr_position(AT_FILE_NAME, ctx))
			break;
	}
put_err_out:
	ntfs_attr_put_search_ctx(ctx);
	if (errno == ENOSPC)
		ntfs_log_trace("No attributes left that could be moved out.\n");
	return -1;
}