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

	if (difference == 0)
		exfat_bug("zero clusters count passed");

	if (node->start_cluster != EXFAT_CLUSTER_FREE)
	{
		/* get the last cluster of the file */
		previous = exfat_advance_cluster(ef, node, current - 1);
		if (CLUSTER_INVALID(previous))
		{
			exfat_error("invalid cluster 0x%x while growing", previous);
			return -EIO;
		}
	}
	else
	{
		if (node->fptr_index != 0)
			exfat_bug("non-zero pointer index (%u)", node->fptr_index);
		/* file does not have clusters (i.e. is empty), allocate
		   the first one for it */
		previous = allocate_cluster(ef, 0);
		if (CLUSTER_INVALID(previous))
			return -ENOSPC;
		node->fptr_cluster = node->start_cluster = previous;
		allocated = 1;
		/* file consists of only one cluster, so it's contiguous */
		node->flags |= EXFAT_ATTRIB_CONTIGUOUS;
	}

	while (allocated < difference)
	{
		next = allocate_cluster(ef, previous + 1);
		if (CLUSTER_INVALID(next))
		{
			if (allocated != 0)
				shrink_file(ef, node, current + allocated, allocated);
			return -ENOSPC;
		}
		if (next != previous - 1 && IS_CONTIGUOUS(*node))
		{
			/* it's a pity, but we are not able to keep the file contiguous
			   anymore */
			make_noncontiguous(ef, node->start_cluster, previous);
			node->flags &= ~EXFAT_ATTRIB_CONTIGUOUS;
			node->flags |= EXFAT_ATTRIB_DIRTY;
		}
		set_next_cluster(ef, IS_CONTIGUOUS(*node), previous, next);
		previous = next;
		allocated++;
	}

	set_next_cluster(ef, IS_CONTIGUOUS(*node), previous, EXFAT_CLUSTER_END);
	return 0;
}
Example #2
0
filesystem::filesystem(const std::string& file)
{
	backing.open(file, std::ios_base::out | std::ios_base::app);
	backing.close();
	backing.open(file, std::ios_base::in | std::ios_base::out | std::ios_base::binary | std::ios_base::ate);
	if(!backing)
		throw std::runtime_error("Can't open file '" + file + "'");
	uint64_t backing_size = backing.tellp();
	backing.seekp(0, std::ios_base::beg);
	if(!backing)
		throw std::runtime_error("Can't get file size.");
	supercluster_count = (backing_size + SUPERCLUSTER_SIZE - 1) / SUPERCLUSTER_SIZE;
	for(unsigned i = 0; i < supercluster_count; i++)
		superclusters[i].load(backing, i);
	if(supercluster_count == 0) {
		allocate_cluster();	//Will allocate cluster 2 (main directory).
		//Write superblock to cluster 1.
		char superblock[CLUSTER_SIZE];
		memset(superblock, 0, CLUSTER_SIZE);
		uint32_t c = 2;
		uint32_t p = 0;
		uint32_t c2, p2;
		write_data(c, p, superblock, CLUSTER_SIZE, c2, p2);
		strcpy(superblock, "sefs-magic");
		c = 1;
		p = 0;
		write_data(c, p, superblock, CLUSTER_SIZE, c2, p2);
	} else {
		//Read superblock from cluster 1.
		char superblock[CLUSTER_SIZE];
		uint32_t c = 1;
		uint32_t p = 0;
		read_data(c, p, superblock, CLUSTER_SIZE);
		if(strcmp(superblock, "sefs-magic"))
			throw std::runtime_error("Bad magic");
	}
}
Example #3
0
/**
* @brief 
*	Function to write into the given file with the contents given
* @param fd
*	File descriptor of the file 
* @param buffer
*	Pointer to the start of the contents which needs to be written into
*	the file
* @param bytes_to_write
*	Indicates the number of bytes which needs to be written into the file
* @return 
*	Integer representing number of bytes successfully written into the file
*/
int file_write(int fd, const char *buffer,int bytes_to_write)
{
	file_info *temp = file_head;
	u8 *file_cont;
	int tmp_offset = bytes_to_write;
	int alloc_cluster_cnt = 0;
	int bytes_to_copy;
	int bytes_written = 0;
	u32 new_cluster;
	u32 prev_cluster;	

	while(temp != NULL){
		if(temp->fd == fd)
			break;
		temp = temp->next;	
	}
	if(temp->mode == FILE_READ){
		sw_printf("File opened in read only mode\n");
		return 0;
	}
	while(tmp_offset > 0){
		if((temp->cur_cluster != 0) && (temp->cur_cluster != END_OF_CLUSTER) 
			&& (temp->cur_cluster != END_OF_ROOT_CLUSTER) && 
			(cluster_size - temp->cur_offset != 0)) {
			file_cont = cluster_to_memory_addr(temp->cur_cluster) 
				    + temp->cur_offset;
			bytes_to_copy = cluster_size - (bytes_to_write - bytes_written);
			bytes_to_copy = bytes_to_copy > 0 ?  
					bytes_to_write - bytes_written: 
					cluster_size;
			bytes_to_copy = cluster_size - temp->cur_offset > bytes_to_copy ?
					bytes_to_copy : cluster_size - temp->cur_offset;
			sw_memcpy(file_cont,buffer + bytes_written,bytes_to_copy);
			bytes_written += bytes_to_copy;
			temp->cur_offset += bytes_to_copy;
			tmp_offset -= bytes_to_copy; 
			prev_cluster = temp->cur_cluster;
			if(temp->cur_offset == cluster_size)
				temp->cur_cluster = get_fat_table_entry(temp->cur_cluster);   
			if(temp->cur_cluster != 0 && temp->cur_cluster != END_OF_CLUSTER
			   && temp->cur_cluster != END_OF_ROOT_CLUSTER
			   && tmp_offset != 0)
				temp->cur_offset = 0;
		}
		else{
			new_cluster = allocate_cluster();
			if(alloc_cluster_cnt == 0 && temp->cur_cluster == 0 
			   && temp->strt_cluster == 0){
				temp->strt_cluster = new_cluster;
				*(u16*)(dir_file_offset + STRT_CLUS_LOW_OFF) = 
					temp->strt_cluster & LOW_CLUSWORD_MASK;
				*(u16*)(dir_file_offset + STRT_CLUS_HIGH_OFF) = 
					(temp->strt_cluster & HIGH_CLUSWORD_MASK) >> 16;

			}
			else 
				write_fat_table(prev_cluster,new_cluster);
			temp->cur_cluster = new_cluster;
			temp->cur_offset = 0;
			alloc_cluster_cnt++;       
		}    
Example #4
0
void filesystem::write_data(uint32_t& cluster, uint32_t& ptr, const void* data, uint32_t length,
	uint32_t& real_cluster, uint32_t& real_ptr)
{
	const char* _data = reinterpret_cast<const char*>(data);
	size_t r = 0;
	bool assigned = false;
	do {
		if(cluster / CLUSTERS_PER_SUPER >= supercluster_count || (cluster % CLUSTERS_PER_SUPER) == 0)
			throw std::runtime_error("Bad cluster to write");
		if(!superclusters[cluster / CLUSTERS_PER_SUPER].clusters[cluster % CLUSTERS_PER_SUPER])
			throw std::runtime_error("Bad cluster to write");
		//Write to end of cluster.
		size_t maxwrite = min(length, max(static_cast<uint32_t>(CLUSTER_SIZE), ptr) - ptr);
		if(maxwrite) {
			char buffer[CLUSTER_SIZE];
			memset(buffer, 0, CLUSTER_SIZE);
			if(!assigned) {
				real_cluster = cluster;
				real_ptr = ptr;
				assigned = true;
			}
			backing.seekp(0, std::ios_base::end);
			uint64_t backing_size = backing.tellp();
			if(backing_size > cluster * CLUSTER_SIZE) {
				backing.seekg(cluster * CLUSTER_SIZE, std::ios_base::beg);
				backing.read(buffer, CLUSTER_SIZE);
			}
			memcpy(buffer + ptr, _data, maxwrite);
			backing.seekp(cluster * CLUSTER_SIZE, std::ios_base::beg);
			backing.write(buffer, CLUSTER_SIZE);
			if(!backing)
				throw std::runtime_error("Can't write data");
			length -= maxwrite;
			_data += maxwrite;
			ptr += maxwrite;
			r += maxwrite;
		}
		if(ptr >= CLUSTER_SIZE) {
			uint32_t n = superclusters[cluster / CLUSTERS_PER_SUPER].clusters[cluster %
				CLUSTERS_PER_SUPER];
			if(n == 0)
				throw std::runtime_error("Bad next cluster when writing");
			else if(n == 0xFFFFFFFFU) {
				if(length > 0)
					throw std::runtime_error("Bad next cluster when writing");
				return;
			}
			else if(n == 1) {
				if(!length) {
					ptr = CLUSTER_SIZE;
					return;
				}
				n = allocate_cluster();
				link_cluster(cluster, n);
				cluster = n;
				ptr = 0;
			} else {
				cluster = n;
				ptr = 0;
			}
		}
	} while(length > 0);
}