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; }
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"); } }
/** * @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++; }
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); }