Beispiel #1
0
int ntfs_inode_close(ntfs_inode *ni)
{
	int res;
#if CACHE_NIDATA_SIZE
	BOOL dirty;
	struct CACHED_NIDATA item;

	if (ni) {
		debug_double_inode(ni->mft_no,0);
		/* do not cache system files : could lead to double entries */
		if (ni->vol && ni->vol->nidata_cache
			&& ((ni->mft_no == FILE_root)
			    || ((ni->mft_no >= FILE_first_user)
				&& !(ni->mrec->flags & MFT_RECORD_IS_4)))) {
			/* If we have dirty metadata, write it out. */
			dirty = NInoDirty(ni) || NInoAttrListDirty(ni);
			if (dirty) {
				res = ntfs_inode_sync(ni);
					/* do a real close if sync failed */
				if (res)
					ntfs_inode_real_close(ni);
			} else
				res = 0;

			if (!res) {
					/* feed idata into cache */
				item.inum = ni->mft_no;
				item.ni = ni;
				item.pathname = (const char*)NULL;
				item.varsize = 0;
				debug_cached_inode(ni);
				ntfs_enter_cache(ni->vol->nidata_cache,
					GENERIC(&item), idata_cache_compare);
			}
		} else {
			/* cache not ready or system file, really close */
			res = ntfs_inode_real_close(ni);
		}
	} else
		res = 0;
#else
	res = ntfs_inode_real_close(ni);
#endif
	return (res);
}
Beispiel #2
0
/**
 * ntfs_inode_close - close an ntfs inode and free all associated memory
 * @ni:		ntfs inode to close
 *
 * Make sure the ntfs inode @ni is clean.
 *
 * If the ntfs inode @ni is a base inode, close all associated extent inodes,
 * then deallocate all memory attached to it, and finally free the ntfs inode
 * structure itself.
 *
 * If it is an extent inode, we disconnect it from its base inode before we
 * destroy it.
 *
 * It is OK to pass NULL to this function, it is just noop in this case.
 *
 * Return 0 on success or -1 on error with errno set to the error code. On
 * error, @ni has not been freed. The user should attempt to handle the error
 * and call ntfs_inode_close() again. The following error codes are defined:
 *
 *	EBUSY	@ni and/or its attribute list runlist is/are dirty and the
 *		attempt to write it/them to disk failed.
 *	EINVAL	@ni is invalid (probably it is an extent inode).
 *	EIO	I/O error while trying to write inode to disk.
 */
int ntfs_inode_close(ntfs_inode *ni)
{
	int ret = -1;

	if (!ni)
		return 0;

	ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no);

	/* If we have dirty metadata, write it out. */
	if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
		if (ntfs_inode_sync(ni)) {
			if (errno != EIO)
				errno = EBUSY;
			goto err;
		}
	}
	/* Is this a base inode with mapped extent inodes? */
	if (ni->nr_extents > 0) {
		while (ni->nr_extents > 0) {
			if (ntfs_inode_close(ni->extent_nis[0])) {
				if (errno != EIO)
					errno = EBUSY;
				goto err;
			}
		}
	} else if (ni->nr_extents == -1) {
		ntfs_inode **tmp_nis;
		ntfs_inode *base_ni;
		s32 i;

		/*
		 * If the inode is an extent inode, disconnect it from the
		 * base inode before destroying it.
		 */
		base_ni = ni->base_ni;
		for (i = 0; i < base_ni->nr_extents; ++i) {
			tmp_nis = base_ni->extent_nis;
			if (tmp_nis[i] != ni)
				continue;
			/* Found it. Disconnect. */
			memmove(tmp_nis + i, tmp_nis + i + 1,
					(base_ni->nr_extents - i - 1) *
					sizeof(ntfs_inode *));
			/* Buffer should be for multiple of four extents. */
			if ((--base_ni->nr_extents) & 3) {
				i = -1;
				break;
			}
			/*
			 * ElectricFence is unhappy with realloc(x,0) as free(x)
			 * thus we explicitly separate these two cases.
			 */
			if (base_ni->nr_extents) {
				/* Resize the memory buffer. */
				tmp_nis = realloc(tmp_nis, base_ni->nr_extents *
						  sizeof(ntfs_inode *));
				/* Ignore errors, they don't really matter. */
				if (tmp_nis)
					base_ni->extent_nis = tmp_nis;
			} else if (tmp_nis)
				free(tmp_nis);
			/* Allow for error checking. */
			i = -1;
			break;
		}

		/*
		 *  We could successfully sync, so only log this error
		 *  and try to sync other inode extents too.
		 */
		if (i != -1)
			ntfs_log_error("Extent inode %lld was not found\n",
				       (long long)ni->mft_no);
	}

	__ntfs_inode_release(ni);
	ret = 0;
err:
	ntfs_log_leave("\n");
	return ret;
}