uint32_t reallocate_cluster_chain(uint32_t first_cluster, uint32_t new_size) { uint32_t next_cluster = first_cluster; uint32_t current_size = BYTES_PER_CLUSTER; uint8_t extending = 0; while (current_size < new_size) { if (FAT_ENTRIES[next_cluster] == FAT_EOFC_ENTRY) { // new size is larger than previous so extend the cluster extending = 1; } if (extending == 1) { FAT_ENTRIES[next_cluster] = find_free_cluster(); DIR_ENTRIES[next_cluster] = DIR_ENTRIES[first_cluster]; } next_cluster = FAT_ENTRIES[next_cluster]; current_size += BYTES_PER_CLUSTER; } if (extending == 0 && FAT_ENTRIES[next_cluster] != FAT_EOFC_ENTRY) { // free clusters since we have shrunk current chain free_cluster_chain(FAT_ENTRIES[next_cluster]); } FAT_ENTRIES[next_cluster] = FAT_EOFC_ENTRY; DIR_ENTRIES[next_cluster] = DIR_ENTRIES[first_cluster]; return first_cluster; }
int syscall_unlink(const char *pathname) { int drive; int curdir_handle; char name_comp[13], conv_name[11], dir_path[501]; struct dir_entry dent; int err; if (strlen(pathname) > 500) return ELONGPATH; parse_path(pathname, &drive, dir_path, name_comp); if (dir_path[0] != 0) { curdir_handle = open_path(drive, dir_path); if (curdir_handle < 0) return curdir_handle; // Error } else { curdir_handle = get_curdir_handle(drive); increment_ref_count(curdir_handle); } // Last file name component. if (convert_name(name_comp, conv_name) < 0) { err = EINVALIDNAME; // Error } else if (find_entry(curdir_handle, conv_name, &dent) == 1) { // Check whether it is a deletable file if ((dent.attrib & (FTYPE_READONLY | FTYPE_DIR | FTYPE_VOLUME)) == 0) { delete_dir_entry(curdir_handle, conv_name); free_cluster_chain(dent.start_cluster); err = 0; } else { err = EACCESS; // Error } } else { err = EFILE_NOT_FOUND; } close_dir(curdir_handle); return err; }
void filesystem::free_cluster_chain(uint32_t cluster) { if(cluster == 2) throw std::runtime_error("Cluster 2 can't be freed"); if(cluster / CLUSTERS_PER_SUPER >= supercluster_count) throw std::runtime_error("Bad cluster to free"); uint32_t oldnext = superclusters[cluster / CLUSTERS_PER_SUPER].clusters[cluster % CLUSTERS_PER_SUPER]; if(oldnext == 0) throw std::runtime_error("Attempted to free free cluster"); if(oldnext == 0xFFFFFFFFU) throw std::runtime_error("Attempted to free system cluster"); superclusters[cluster / CLUSTERS_PER_SUPER].clusters[cluster % CLUSTERS_PER_SUPER] = 0; //If there is no next block, or the next block is in different supercluster, save the cluster table. if(oldnext == 1 || oldnext / CLUSTERS_PER_SUPER != cluster / CLUSTERS_PER_SUPER) superclusters[cluster / CLUSTERS_PER_SUPER].save(backing, cluster / CLUSTERS_PER_SUPER); if(oldnext != 1) free_cluster_chain(oldnext); }