Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
Virtualization
zerofree
sparsify.c
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File sparsify.c of Package zerofree
/* * sparsify - a tool to make files on an ext2 filesystem sparse * * Copyright (C) 2004-2012 R M Yorston * * This file may be redistributed under the terms of the GNU General Public * License, version 2. */ #include <ext2fs/ext2fs.h> #include <stdio.h> #include <unistd.h> #include <string.h> #define USAGE "usage: %s [-n] [-v] filesystem filename ...\n" /* initially assume pre-ext4 API version */ #define API 140 #if defined(BLOCK_FLAG_READ_ONLY) #undef API #define API 141 #endif #if defined(EXT2_FLAG_64BITS) #undef API #define API 142 #endif struct process_data { unsigned char *buf; int verbose; int dryrun; blk_t count; blk_t blocks; blk_t total_blocks; int old_percent; }; static int process(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, blk_t ref_block, int ref_offset, void *priv) { struct process_data *p; errcode_t errcode; int i, group; int ret = 0; p = (struct process_data *)priv; p->blocks++; if ( blockcnt >= 0 ) { errcode = io_channel_read_blk(fs->io, *blocknr, 1, p->buf); if ( errcode ) { return BLOCK_ABORT; } for ( i=0; i < fs->blocksize; ++i ) { if ( p->buf[i] ) { break; } } if ( i == fs->blocksize ) { p->count++; if ( !p->dryrun ) { ext2fs_unmark_block_bitmap(fs->block_map, *blocknr); group = ext2fs_group_of_blk(fs, *blocknr); #if API >= 142 ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group)+1); ext2fs_free_blocks_count_add(fs->super, (blk64_t)1); #else fs->group_desc[group].bg_free_blocks_count++; fs->super->s_free_blocks_count++; #endif #if API >= 141 ext2fs_group_desc_csum_set(fs, group); #endif *blocknr = 0; ret = BLOCK_CHANGED; } } if ( p->verbose ) { double percent; percent = 100.0 * (double)p->blocks/(double)p->total_blocks; if ( (int)(percent*10) != p->old_percent ) { fprintf(stderr, "\r%4.1f%%", percent); p->old_percent = (int)(percent*10); } } } return ret; } int main(int argc, char **argv) { int verbose = 0; int dryrun = 0; errcode_t ret; int flags; int superblock = 0; int open_flags = EXT2_FLAG_RW; int iter_flags = 0; int blocksize = 0; ext2_filsys fs = NULL; struct ext2_inode inode; ext2_ino_t root, cwd, inum; int i, c; struct process_data pdata; while ( (c=getopt(argc, argv, "nv")) != -1 ) { switch (c) { case 'n' : dryrun = 1; #if defined(BLOCK_FLAG_READ_ONLY) iter_flags |= BLOCK_FLAG_READ_ONLY; #endif break; case 'v' : verbose = 1; break; default : fprintf(stderr, USAGE, argv[0]); return 1; } } if ( argc < optind+2 ) { fprintf(stderr, USAGE, argv[0]); return 1; } ret = ext2fs_check_if_mounted(argv[optind], &flags); if ( ret ) { fprintf(stderr, "%s: failed to determine filesystem mount state %s\n", argv[0], argv[optind]); return 1; } if ( flags & EXT2_MF_MOUNTED ) { fprintf(stderr, "%s: filesystem %s is mounted\n", argv[0], argv[optind]); return 1; } ret = ext2fs_open(argv[optind], open_flags, superblock, blocksize, unix_io_manager, &fs); if ( ret ) { fprintf(stderr, "%s: failed to open filesystem %s\n", argv[0], argv[optind]); return 1; } pdata.buf = (unsigned char *)malloc(fs->blocksize); if ( pdata.buf == NULL ) { fprintf(stderr, "%s: out of memory (surely not?)\n", argv[0]); return 1; } ret = ext2fs_read_inode_bitmap(fs); if ( ret ) { fprintf(stderr, "%s: error while reading inode bitmap\n", argv[0]); return 1; } ret = ext2fs_read_block_bitmap(fs); if ( ret ) { fprintf(stderr, "%s: error while reading block bitmap\n", argv[0]); return 1; } root = cwd = EXT2_ROOT_INO; for ( i=optind+1; i<argc; ++i ) { ret = ext2fs_namei(fs, root, cwd, argv[i], &inum); if ( ret ) { fprintf(stderr, "%s: failed to find file %s\n", argv[0], argv[i]); continue; } ret = ext2fs_read_inode(fs, inum, &inode); if ( ret ) { fprintf(stderr, "%s: failed to open inode %d\n", argv[0], inum); continue; } if ( !ext2fs_inode_has_valid_blocks(&inode) ) { fprintf(stderr, "%s: file %s has no valid blocks\n", argv[0], argv[i]); continue; } #if defined(EXT4_EXTENTS_FL) && API < 141 if ( inode.i_flags & EXT4_EXTENTS_FL ) { fprintf(stderr, "%s: unable to process %s, it uses extents\n", argv[0], argv[i]); continue; } #endif #if defined(EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && defined(EXT4_HUGE_FILE_FL) if ( (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && (inode.i_flags & EXT4_HUGE_FILE_FL) ) { fprintf(stderr, "%s: unable to process %s, it's huge\n", argv[0], argv[i]); continue; } #endif if ( verbose ) { printf("processing %s\n", argv[i]); } pdata.verbose = verbose; pdata.dryrun = dryrun; pdata.count = pdata.blocks = 0; pdata.total_blocks = inode.i_blocks/(fs->blocksize >> 9); pdata.old_percent = 1000; ret = ext2fs_block_iterate2(fs, inum, iter_flags, NULL, process, &pdata); if ( ret ) { fprintf(stderr, "%s: failed to process file %s\n", argv[0], argv[i]); continue; } if ( pdata.count && !dryrun ) { ext2fs_mark_bb_dirty(fs); ext2fs_mark_super_dirty(fs); ret = ext2fs_read_inode(fs, inum, &inode); if ( ret ) { fprintf(stderr, "%s: failed to open inode (%s)\n", argv[0], argv[i]); continue; } #if API >= 141 ret = ext2fs_iblk_sub_blocks(fs, &inode, (blk64_t)pdata.count); if ( ret ) { fprintf(stderr, "%s: failed to update block count (%s)\n", argv[0], argv[i]); continue; } #else inode.i_blocks -= pdata.count * (fs->blocksize >> 9); #endif ret = ext2fs_write_inode(fs, inum, &inode); if ( ret ) { fprintf(stderr, "%s: failed to write inode (%s)\n", argv[0], argv[i]); continue; } } if ( verbose ) { printf("\r%d/%d/%d %s\n", pdata.count, pdata.blocks, pdata.total_blocks, argv[i]); } } ret = ext2fs_close(fs); if ( ret ) { fprintf(stderr, "%s: error while closing filesystem\n", argv[0]); return 1; } return 0; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor