static int exfat_copy(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file) { char *new_file; FILE *f_out; const struct exfat_dir_struct *ls=(const struct exfat_dir_struct*)dir_data->private_dir_data; const struct exfat_super_block *exfat_header=ls->boot_sector; const unsigned int cluster_shift=exfat_header->block_per_clus_bits + exfat_header->blocksize_bits; unsigned char *buffer_file=(unsigned char *)MALLOC(1<<cluster_shift); unsigned int cluster; uint64_t file_size=file->st_size; exfat_method_t exfat_meth=exFAT_FOLLOW_CLUSTER; uint64_t start_exfat1,clus_blocknr; unsigned long int total_clusters; f_out=fopen_local(&new_file, dir_data->local_dir, dir_data->current_directory); if(!f_out) { log_critical("Can't create file %s: \n",new_file); free(new_file); free(buffer_file); return -1; } cluster = file->st_ino; start_exfat1=le32(exfat_header->fat_blocknr) << exfat_header->blocksize_bits; clus_blocknr=le32(exfat_header->clus_blocknr); total_clusters=le32(exfat_header->total_clusters); log_trace("exfat_copy dst=%s first_cluster=%u (%llu) size=%lu\n", new_file, cluster, (long long unsigned)(((cluster-2) << exfat_header->block_per_clus_bits) + clus_blocknr), (long unsigned)file_size); while(cluster>=2 && cluster<=total_clusters && file_size>0) { unsigned int toread = 1 << cluster_shift; if (toread > file_size) toread = file_size; if((unsigned)exfat_read_cluster(disk, partition, exfat_header, buffer_file, cluster) < toread) { log_error("exfat_copy: Can't read cluster %u.\n", cluster); } if(fwrite(buffer_file, 1, toread, f_out) != toread) { log_error("exfat_copy: no space left on destination.\n"); fclose(f_out); set_date(new_file, file->td_atime, file->td_mtime); free(new_file); free(buffer_file); return -1; } file_size -= toread; if(file_size>0) { if(exfat_meth==exFAT_FOLLOW_CLUSTER) { const unsigned int next_cluster=exfat_get_next_cluster(disk, partition, start_exfat1, cluster); if(next_cluster>=2 && next_cluster<=total_clusters) cluster=next_cluster; else if(cluster==file->st_ino && next_cluster==0) exfat_meth=exFAT_NEXT_FREE_CLUSTER; /* Recovery of a deleted file */ else exfat_meth=exFAT_NEXT_CLUSTER; /* exFAT is corrupted, don't trust it */ } if(exfat_meth==exFAT_NEXT_CLUSTER) cluster++; else if(exfat_meth==exFAT_NEXT_FREE_CLUSTER) { /* Deleted file are composed of "free" clusters */ while(++cluster<total_clusters && exfat_get_next_cluster(disk, partition, start_exfat1, cluster)!=0); } } } fclose(f_out); set_date(new_file, file->td_atime, file->td_mtime); free(new_file); free(buffer_file); return 0; }
unsigned int exfat_remove_used_space(disk_t *disk, const partition_t *partition, alloc_data_t *list_search_space) { struct exfat_super_block *exfat_header; unsigned int cluster_shift; /* Load boot sector */ exfat_header=(struct exfat_super_block *)MALLOC(0x200); if(disk->pread(disk, exfat_header, 0x200, partition->part_offset) != 0x200) { log_error("Can't read exFAT boot sector.\n"); free(exfat_header); return 0; } cluster_shift=exfat_header->block_per_clus_bits + exfat_header->blocksize_bits; /* Load bitmap information */ { const struct exfat_alloc_bitmap_entry *bitmap; const uint64_t start=partition->part_offset + exfat_cluster_to_offset(exfat_header, le32(exfat_header->rootdir_clusnr)); unsigned char *buffer_rootdir=(unsigned char *)MALLOC(1<<cluster_shift); unsigned char *buffer; unsigned int i; unsigned int cluster_bitmap; const uint64_t start_exfat1=(uint64_t)le32(exfat_header->fat_blocknr) << exfat_header->blocksize_bits; uint64_t start_free=0; uint64_t end_free=0; if(disk->pread(disk, buffer_rootdir, 1 << cluster_shift, start) != (1<<cluster_shift)) { log_error("exFAT: Can't root directory cluster.\n"); free(buffer_rootdir); free(exfat_header); return 0; } bitmap=exfat_get_bitmap(buffer_rootdir, 1<<cluster_shift); if(bitmap==NULL) { log_error("exFAT: Can't find bitmap.\n"); free(buffer_rootdir); free(exfat_header); return 0; } cluster_bitmap=le32(bitmap->first_cluster); log_trace("exfat_remove_used_space\n"); buffer=(unsigned char *)MALLOC(1<<cluster_shift); for(i=2; i<le32(exfat_header->total_clusters)+2; i++) { const unsigned int offset_o=(i-2)%(8<<cluster_shift); if(offset_o==0) { exfat_read_cluster(disk, partition, exfat_header, buffer, cluster_bitmap); cluster_bitmap=get_next_cluster(disk, partition, UP_FAT32, start_exfat1, cluster_bitmap); } if(((buffer[offset_o/8]>>(offset_o%8))&1) != 0) { /* Not free */ if(end_free+1==partition->part_offset + exfat_cluster_to_offset(exfat_header, i)) end_free+=(1<<cluster_shift); else { if(start_free != end_free) del_search_space(list_search_space, start_free, end_free); start_free=partition->part_offset + exfat_cluster_to_offset(exfat_header, i); end_free=start_free + (1<<cluster_shift) - 1; } } } free(buffer); if(start_free != end_free) del_search_space(list_search_space, start_free, end_free); free(buffer_rootdir); free(exfat_header); } return (1<<cluster_shift); }
static int exfat_dir(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_cluster, file_info_t *dir_list) { const struct exfat_dir_struct *ls=(const struct exfat_dir_struct*)dir_data->private_dir_data; const struct exfat_super_block*exfat_header=ls->boot_sector; const unsigned int cluster_shift=exfat_header->block_per_clus_bits + exfat_header->blocksize_bits; unsigned int cluster; unsigned char *buffer_dir=(unsigned char *)MALLOC(NBR_CLUSTER_MAX << cluster_shift); unsigned int nbr_cluster; const unsigned int total_clusters=le32(exfat_header->total_clusters); exfat_method_t exfat_meth=exFAT_FOLLOW_CLUSTER; int stop=0; const uint64_t start_exfat1=le32(exfat_header->fat_blocknr) << exfat_header->blocksize_bits; if(first_cluster<2) cluster=le32(exfat_header->rootdir_clusnr); else cluster=first_cluster; memset(buffer_dir, 0, NBR_CLUSTER_MAX<<cluster_shift); nbr_cluster=0; while(!is_EOC(cluster) && cluster>=2 && nbr_cluster<NBR_CLUSTER_MAX && stop==0) { if(exfat_read_cluster(disk, partition, exfat_header, buffer_dir + ((uint64_t) nbr_cluster << cluster_shift), cluster) != (1<<cluster_shift)) { log_error("exFAT: Can't read directory cluster.\n"); stop=1; } if(stop==0) { if(exfat_meth==exFAT_FOLLOW_CLUSTER) { const unsigned int next_cluster=exfat_get_next_cluster(disk, partition, start_exfat1, cluster); if((next_cluster>=2 && next_cluster<=total_clusters) || is_EOC(next_cluster)) cluster=next_cluster; else if(next_cluster==0) { #if 0 /* FIXME: experimental */ if(cluster==first_cluster && (dir_data->param & FLAG_LIST_DELETED)==FLAG_LIST_DELETED) exfat_meth=exFAT_NEXT_FREE_CLUSTER; /* Recovery of a deleted directory */ else cluster=0; /* Stop directory listing */ #else cluster=0; /* Stop directory listing */ #endif } else exfat_meth=exFAT_NEXT_CLUSTER; /* exFAT is corrupted, don't trust it */ } if(exfat_meth==exFAT_NEXT_CLUSTER) cluster++; else if(exfat_meth==exFAT_NEXT_FREE_CLUSTER) { /* Deleted directories are composed of "free" clusters */ #if 0 while(++cluster<total_clusters && exfat_get_next_cluster(disk, partition, start_exfat1, cluster)!=0); #endif } nbr_cluster++; } } if(nbr_cluster>0) dir_exfat_aux(buffer_dir, nbr_cluster<<cluster_shift, dir_data, dir_list); free(buffer_dir); return 0; }