Example #1
0
static int shrink_file(struct exfat* ef, struct exfat_node* node,
		uint32_t current, uint32_t difference)
{
	cluster_t previous;
	cluster_t next;

	if (difference == 0)
		exfat_bug("zero difference passed");
	if (node->start_cluster == EXFAT_CLUSTER_FREE)
		exfat_bug("unable to shrink empty file (%u clusters)", current);
	if (current < difference)
		exfat_bug("file underflow (%u < %u)", current, difference);

	/* crop the file */
	if (current > difference)
	{
		cluster_t last = exfat_advance_cluster(ef, node,
				current - difference - 1);
		if (CLUSTER_INVALID(last))
		{
			exfat_error("invalid cluster 0x%x while shrinking", last);
			return -EIO;
		}
		previous = exfat_next_cluster(ef, node, last);
		if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), last,
				EXFAT_CLUSTER_END))
			return -EIO;
	}
	else
	{
		previous = node->start_cluster;
		node->start_cluster = EXFAT_CLUSTER_FREE;
	}
	node->fptr_index = 0;
	node->fptr_cluster = node->start_cluster;

	/* free remaining clusters */
	while (difference--)
	{
		if (CLUSTER_INVALID(previous))
		{
			exfat_error("invalid cluster 0x%x while freeing after shrink",
					previous);
			return -EIO;
		}
		next = exfat_next_cluster(ef, node, previous);
		if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), previous,
				EXFAT_CLUSTER_FREE))
			return -EIO;
		free_cluster(ef, previous);
		previous = next;
	}
	return 0;
}
Example #2
0
static int erase_range(struct exfat* ef, struct exfat_node* node,
		uint64_t begin, uint64_t end)
{
	uint64_t cluster_boundary;
	cluster_t cluster;

	if (begin >= end)
		return 0;

	cluster_boundary = (begin | (CLUSTER_SIZE(*ef->sb) - 1)) + 1;
	cluster = exfat_advance_cluster(ef, node,
			begin / CLUSTER_SIZE(*ef->sb));
	if (CLUSTER_INVALID(cluster))
	{
		exfat_error("invalid cluster 0x%x while erasing", cluster);
		return -EIO;
	}
	/* erase from the beginning to the closest cluster boundary */
	erase_raw(ef, MIN(cluster_boundary, end) - begin,
			exfat_c2o(ef, cluster) + begin % CLUSTER_SIZE(*ef->sb));
	/* erase whole clusters */
	while (cluster_boundary < end)
	{
		cluster = exfat_next_cluster(ef, node, cluster);
		/* the cluster cannot be invalid because we have just allocated it */
		if (CLUSTER_INVALID(cluster))
			exfat_bug("invalid cluster 0x%x after allocation", cluster);
		erase_raw(ef, CLUSTER_SIZE(*ef->sb), exfat_c2o(ef, cluster));
		cluster_boundary += CLUSTER_SIZE(*ef->sb);
	}
	return 0;
}
Example #3
0
static int nodeck(struct exfat* ef, struct exfat_node* node)
{
	const cluster_t cluster_size = CLUSTER_SIZE(*ef->sb);
	cluster_t clusters = (node->size + cluster_size - 1) / cluster_size;
	cluster_t c = node->start_cluster;
	int rc = 0;

	while (clusters--)
	{
		if (CLUSTER_INVALID(c))
		{
			char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];

			exfat_get_name(node, name, sizeof(name) - 1);
			exfat_error("file '%s' has invalid cluster 0x%x", name, c);
			rc = 1;
			break;
		}
		if (BMAP_GET(ef->cmap.chunk, c - EXFAT_FIRST_DATA_CLUSTER) == 0)
		{
			char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];

			exfat_get_name(node, name, sizeof(name) - 1);
			exfat_error("cluster 0x%x of file '%s' is not allocated", c, name);
			rc = 1;
		}
		c = exfat_next_cluster(ef, node, c);
	}
	return rc;
}
static int fetch_next_entry(struct exfat* ef, const struct exfat_node* parent,
		struct iterator* it)
{
	/* move iterator to the next entry in the directory */
	it->offset += sizeof(struct exfat_entry);
	/* fetch the next cluster if needed */
	if ((it->offset & (CLUSTER_SIZE(*ef->sb) - 1)) == 0)
	{
		/* reached the end of directory; the caller should check this
		   condition too */
		if (it->offset >= parent->size)
			return 0;
		it->cluster = exfat_next_cluster(ef, parent, it->cluster);
		if (CLUSTER_INVALID(it->cluster))
		{
			exfat_error("invalid cluster 0x%x while reading directory",
					it->cluster);
			return 1;
		}
		if (exfat_pread(ef->dev, it->chunk, CLUSTER_SIZE(*ef->sb),
				exfat_c2o(ef, it->cluster)) < 0)
		{
			exfat_error("failed to read the next directory cluster %#x",
					it->cluster);
			return 1;
		}
	}
	return 0;
}
Example #5
0
static uint64_t rootdir_size(const struct exfat* ef)
{
	uint32_t clusters = 0;
	uint32_t clusters_max = le32_to_cpu(ef->sb->cluster_count);
	cluster_t rootdir_cluster = le32_to_cpu(ef->sb->rootdir_cluster);

	/* Iterate all clusters of the root directory to calculate its size.
	   It can't be contiguous because there is no flag to indicate this. */
	do
	{
		if (clusters == clusters_max) /* infinite loop detected */
		{
			exfat_error("root directory cannot occupy all %d clusters",
					clusters);
			return 0;
		}
		if (CLUSTER_INVALID(rootdir_cluster))
		{
			exfat_error("bad cluster %#x while reading root directory",
					rootdir_cluster);
			return 0;
		}
		rootdir_cluster = exfat_next_cluster(ef, ef->root, rootdir_cluster);
		clusters++;
	}
	while (rootdir_cluster != EXFAT_CLUSTER_END);

	return (uint64_t) clusters * CLUSTER_SIZE(*ef->sb);
}
static void next_entry(struct exfat* ef, const struct exfat_node* parent,
		cluster_t* cluster, off64_t* offset)
{
	*offset += sizeof(struct exfat_entry);
	if (*offset % CLUSTER_SIZE(*ef->sb) == 0)
		/* next cluster cannot be invalid */
		*cluster = exfat_next_cluster(ef, parent, *cluster);
}
Example #7
0
ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
		const void* buffer, size_t size, off64_t offset)
{
	cluster_t cluster;
	const char* bufp = buffer;
	off64_t lsize, loffset, remainder;

	if (offset > node->size)
		if (exfat_truncate(ef, node, offset, true) != 0)
			return -1;
	if (offset + size > node->size)
		if (exfat_truncate(ef, node, offset + size, false) != 0)
			return -1;
	if (size == 0)
		return 0;

	cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
	if (CLUSTER_INVALID(cluster))
	{
		exfat_error("invalid cluster 0x%x while writing", cluster);
		return -1;
	}

	loffset = offset % CLUSTER_SIZE(*ef->sb);
	remainder = size;
	while (remainder > 0)
	{
		if (CLUSTER_INVALID(cluster))
		{
			exfat_error("invalid cluster 0x%x while writing", cluster);
			return -1;
		}
		lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
		if (exfat_pwrite(ef->dev, bufp, lsize,
				exfat_c2o(ef, cluster) + loffset) < 0)
		{
			exfat_error("failed to write cluster %#x", cluster);
			ef->was_dirty = true; // Leaves the volume "mounted", to force chkdsk on it.
			return -1;
		}
		bufp += lsize;
		loffset = 0;
		remainder -= lsize;
		cluster = exfat_next_cluster(ef, node, cluster);
	}
	exfat_update_mtime(node);
	return size - remainder;
}
Example #8
0
static bool next_entry(struct exfat* ef, const struct exfat_node* parent,
		cluster_t* cluster, off_t* offset)
{
	*offset += sizeof(struct exfat_entry);
	if (*offset % CLUSTER_SIZE(*ef->sb) == 0)
	{
		*cluster = exfat_next_cluster(ef, parent, *cluster);
		if (CLUSTER_INVALID(*cluster))
		{
			exfat_error("invalid cluster %#x while getting next entry",
					*cluster);
			return false;
		}
	}
	return true;
}
Example #9
0
ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
		void* buffer, size_t size, off64_t offset)
{
	cluster_t cluster;
	char* bufp = buffer;
	off64_t lsize, loffset, remainder;

	if (offset >= node->size)
		return 0;
	if (size == 0)
		return 0;

	cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
	if (CLUSTER_INVALID(cluster))
	{
		exfat_error("invalid cluster 0x%x while reading", cluster);
		return -1;
	}

	loffset = offset % CLUSTER_SIZE(*ef->sb);
	remainder = MIN(size, node->size - offset);
	while (remainder > 0)
	{
		if (CLUSTER_INVALID(cluster))
		{
			exfat_error("invalid cluster 0x%x while reading", cluster);
			return -1;
		}
		lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
		if (exfat_pread(ef->dev, bufp, lsize,
					exfat_c2o(ef, cluster) + loffset) < 0)
		{
			exfat_error("failed to read cluster %#x", cluster);
			return -1;
		}
		bufp += lsize;
		loffset = 0;
		remainder -= lsize;
		cluster = exfat_next_cluster(ef, node, cluster);
	}
	if (!ef->ro && !ef->noatime)
		exfat_update_atime(node);
	return MIN(size, node->size - offset) - remainder;
}
static int fetch_next_entry(struct exfat* ef, const struct exfat_node* parent,
                            struct iterator* it)
{
    /* move iterator to the next entry in the directory */
    it->offset += sizeof(struct exfat_entry);
    /* fetch the next cluster if needed */
    if ((it->offset & (CLUSTER_SIZE(*ef->sb) - 1)) == 0)
    {
        it->cluster = exfat_next_cluster(ef, parent, it->cluster);
        if (CLUSTER_INVALID(it->cluster))
        {
            exfat_error("invalid cluster while reading directory");
            return 1;
        }
        exfat_read_raw(it->chunk, CLUSTER_SIZE(*ef->sb),
                       exfat_c2o(ef, it->cluster), ef->fd);
    }
    return 0;
}
Example #11
0
ssize_t exfat_write(struct exfat* ef, struct exfat_node* node,
		const void* buffer, size_t size, off_t offset)
{
	cluster_t cluster;
	const char* bufp = buffer;
	off_t lsize, loffset, remainder;

	if (offset + size > node->size)
	{
		int rc = exfat_truncate(ef, node, offset + size);
		if (rc != 0)
			return rc;
	}
	if (size == 0)
		return 0;

	cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
	if (CLUSTER_INVALID(cluster))
	{
		exfat_error("got invalid cluster");
		return -1;
	}

	loffset = offset % CLUSTER_SIZE(*ef->sb);
	remainder = size;
	while (remainder > 0)
	{
		if (CLUSTER_INVALID(cluster))
		{
			exfat_error("got invalid cluster");
			return -1;
		}
		lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
		exfat_write_raw(bufp, lsize, exfat_c2o(ef, cluster) + loffset, ef->fd);
		bufp += lsize;
		loffset = 0;
		remainder -= lsize;
		cluster = exfat_next_cluster(ef, node, cluster);
	}
	exfat_update_mtime(node);
	return size - remainder;
}
Example #12
0
cluster_t exfat_advance_cluster(const struct exfat* ef,
		struct exfat_node* node, uint32_t count)
{
	uint32_t i;

	if (node->fptr_index > count)
	{
		node->fptr_index = 0;
		node->fptr_cluster = node->start_cluster;
	}

	for (i = node->fptr_index; i < count; i++)
	{
		node->fptr_cluster = exfat_next_cluster(ef, node, node->fptr_cluster);
		if (CLUSTER_INVALID(node->fptr_cluster))
			break; /* the caller should handle this and print appropriate 
			          error message */
	}
	node->fptr_index = count;
	return node->fptr_cluster;
}
Example #13
0
ssize_t exfat_read(const struct exfat* ef, struct exfat_node* node,
		void* buffer, size_t size, off_t offset)
{
	cluster_t cluster;
	char* bufp = buffer;
	off_t lsize, loffset, remainder;

	if (offset >= node->size)
		return 0;
	if (size == 0)
		return 0;

	cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb));
	if (CLUSTER_INVALID(cluster))
	{
		exfat_error("got invalid cluster");
		return -1;
	}

	loffset = offset % CLUSTER_SIZE(*ef->sb);
	remainder = MIN(size, node->size - offset);
	while (remainder > 0)
	{
		if (CLUSTER_INVALID(cluster))
		{
			exfat_error("got invalid cluster");
			return -1;
		}
		lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
		exfat_read_raw(bufp, lsize, exfat_c2o(ef, cluster) + loffset, ef->fd);
		bufp += lsize;
		loffset = 0;
		remainder -= lsize;
		cluster = exfat_next_cluster(ef, node, cluster);
	}
	if (!ef->ro && !ef->noatime)
		exfat_update_atime(node);
	return size - remainder;
}