/* * This clever recursive function handles i_blocks[] as well as * indirect, double indirect, and triple indirect blocks. It iterates * over the entries in the i_blocks array or indirect blocks, and for * each one, will recursively handle any indirect blocks and then * frees and deallocates the blocks. */ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, char *block_buf, blk_t *p, int level, blk_t start, blk_t count, int max) { errcode_t retval; blk_t b; int i; blk64_t offset, incr; int freed = 0; #ifdef PUNCH_DEBUG printf("Entering ind_punch, level %d, start %u, count %u, " "max %d\n", level, start, count, max); #endif incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super)-2)*level); for (i=0, offset=0; i < max; i++, p++, offset += incr) { if (offset >= start + count) break; if (*p == 0 || (offset+incr) <= start) continue; b = *p; if (level > 0) { blk_t start2; #ifdef PUNCH_DEBUG printf("Reading indirect block %u\n", b); #endif retval = ext2fs_read_ind_block(fs, b, block_buf); if (retval) return retval; start2 = (start > offset) ? start - offset : 0; retval = ind_punch(fs, inode, block_buf + fs->blocksize, (blk_t *) block_buf, level - 1, start2, count - offset, fs->blocksize >> 2); if (retval) return retval; retval = ext2fs_write_ind_block(fs, b, block_buf); if (retval) return retval; if (!check_zero_block(block_buf, fs->blocksize)) continue; } #ifdef PUNCH_DEBUG printf("Freeing block %u (offset %llu)\n", b, offset); #endif ext2fs_block_alloc_stats(fs, b, -1); *p = 0; freed++; }
errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags) { unsigned int group, left, c, d; char *buf, *cp; blk_t blk; ssize_t actual; errcode_t retval; buf = malloc(fs->blocksize * BUF_BLOCKS); if (!buf) return ENOMEM; for (group = 0; group < fs->group_desc_count; group++) { blk = fs->group_desc[(unsigned)group].bg_inode_table; if (!blk) { retval = EXT2_ET_MISSING_INODE_TABLE; goto errout; } left = fs->inode_blocks_per_group; while (left) { c = BUF_BLOCKS; if (c > left) c = left; retval = io_channel_read_blk(fs->io, blk, c, buf); if (retval) goto errout; cp = buf; while (c) { if (!(flags & IMAGER_FLAG_SPARSEWRITE)) { d = c; goto skip_sparse; } /* Skip zero blocks */ if (check_zero_block(cp, fs->blocksize)) { c--; blk++; left--; cp += fs->blocksize; lseek(fd, fs->blocksize, SEEK_CUR); continue; } /* Find non-zero blocks */ for (d=1; d < c; d++) { if (check_zero_block(cp + d*fs->blocksize, fs->blocksize)) break; } skip_sparse: actual = write(fd, cp, fs->blocksize * d); if (actual == -1) { retval = errno; goto errout; } if (actual != (ssize_t) (fs->blocksize * d)) { retval = EXT2_ET_SHORT_WRITE; goto errout; } blk += d; left -= d; cp += fs->blocksize * d; c -= d; } } } retval = 0; errout: free(buf); return retval; }