/*************************************************************************** * Copyright (C) 2011 by Roberto Maar * * robi@users.berlios.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ***************************************************************************/ // The Magic functions for ext4 need a small stack to the cache found extents // The extent_db.c functions provide the interface for this. #ifdef HAVE_CONFIG_H #include #endif #include #include #include "extent_db.h" extern ext2_filsys current_fs; static int mark_extent_len(struct extent_db_t*, blk_t, void*); struct extent_area* new_extent_area(){ struct extent_area *ea; ea = malloc(sizeof(struct extent_area)); if (ea) memset(ea, 0, sizeof(struct extent_area)); return (ea) ? ea : NULL; } static struct extent_db_item* new_item(struct extent_db_item *last){ struct extent_db_item *this = NULL; this = malloc(sizeof(struct extent_db_item)); if (this){ this->last = last; this->entry = NULL; this->next = NULL; return this; } return NULL; } struct extent_db_t* extent_db_init(ext2fs_block_bitmap d_bmap){ struct extent_db_t* db = NULL; db = malloc(sizeof(struct extent_db_t)); if (db){ db->count = 0; db->max_depth = 0; db->d_bmap = d_bmap; db->next = new_item((struct extent_db_item*)db); } return db; } int extent_db_add (struct extent_db_t* db, struct extent_area *ea, int flag){ struct extent_db_item *pointer; pointer = db->next; while (pointer->entry) pointer = pointer->next; //FIXME if ((pointer->last != (struct extent_db_item*)db) && (pointer->last->entry) && (pointer->last->entry->end_b == ea->start_b -1) && (ea->l_start)){ pointer->last->entry->len += ea->len; pointer->last->entry->end_b += ea->len; pointer->last->entry->size += (unsigned long long)ea->len * current_fs->blocksize; free (ea); return db->count; } pointer->next = new_item(pointer); if (pointer->next){ pointer->entry = ea; if (db->max_depth < ea->depth) db->max_depth = ea->depth; (db->count)++; if (flag) mark_extent_len(db, ea->blocknr, NULL ); else { ea->end_b = ea->start_b + ea->len -1; ea->size = (unsigned long long)ea->len * current_fs->blocksize; } return db->count; } return 0; } __u32 extentd_db_find( struct extent_db_t*db ,__u32 start, struct extent_area *ea) { struct extent_db_item *pointer; __u32 end = 0; __u16 depth; depth = db->max_depth+1; while ((depth) && (!end)){ pointer = db->next; while ((pointer->entry) && ((pointer->entry->depth != depth - 1) || (pointer->entry->l_start != start))) pointer = pointer->next; if (pointer->entry){ memcpy(ea,pointer->entry,sizeof(struct extent_area)); end = pointer->entry->l_end; } else{ if ((depth - 1) && (!start)) (db->max_depth)--; depth--; } } //depth return end; } int extent_db_del(struct extent_db_t* db,blk_t blk){ struct extent_db_item *pointer; int ret = 0; pointer = db->next; while ((pointer->entry) && (pointer->entry->blocknr < blk)) pointer = pointer->next; if ((pointer->entry) && (pointer->entry->blocknr == blk)){ (pointer->last)->next = pointer->next; pointer->next->last = pointer->last; if(pointer->entry) free(pointer->entry); if (pointer) free(pointer); (db->count)--; // printf("Extend DB : entry %lu deleted\n",blk); ret = 1; } return ret; } static void clear_entry(struct extent_db_item *p){ if (p->next) clear_entry(p->next); if (p->entry) { // printf("EXT-DB : %10u %d %10lu %10lu %10lu\n",p->entry->blocknr, (p->entry->l_start)?1:0, p->entry->start_b, p->entry->end_b, p->entry->len); free(p->entry); } if (p) free(p); return; } void extent_db_clear(struct extent_db_t* db){ // printf("Extent DB has %lu Entries ; clean now\n",db->count); clear_entry(db->next); if(db) free(db); return; } static int mark_extent_len(struct extent_db_t* db, blk_t blk, void * buf){ void *buf_tmp = NULL; int bufset = 0; int ret = 0; struct ext3_extent_idx *idx; struct ext3_extent *extent; struct ext3_extent_header *header; int entry,i; if (!buf){ buf = malloc(current_fs->blocksize); io_channel_read_blk (current_fs->io, blk, 1, buf ); bufset=1; } buf_tmp = malloc(current_fs->blocksize); if ((!buf_tmp) || (!buf)) return 1; header = buf; ret = ext2fs_extent_header_verify((void*) header, current_fs->blocksize); ext2fs_unmark_generic_bitmap(db->d_bmap, blk); if(!ret){ for (entry =1; ((!ret) && (entry <= ext2fs_le16_to_cpu(header->eh_entries))) ; entry++){ if (ext2fs_le16_to_cpu(header->eh_depth)){ idx = (struct ext3_extent_idx*) (header + entry); if(io_channel_read_blk ( current_fs->io,ext2fs_le32_to_cpu(idx->ei_leaf), 1, buf_tmp )){ fprintf(stderr,"Error read block %lu\n", (long unsigned int)ext2fs_le32_to_cpu(idx->ei_leaf)); ret = 2; } else{ //Recursion if (! extent_db_del(db,ext2fs_le32_to_cpu(idx->ei_leaf))) ret = mark_extent_len(db, ext2fs_le32_to_cpu(idx->ei_leaf),buf_tmp); } } else{ extent = (struct ext3_extent*)(header + entry); for (i = 0; i< ext2fs_le16_to_cpu(extent->ee_len); i++){ ext2fs_unmark_generic_bitmap(db->d_bmap, ext2fs_le32_to_cpu(extent->ee_start) + i ); } } } } if (buf_tmp) free(buf_tmp); if (bufset && buf) free(buf); return ret; }