Developped an option --unused-fast for faster ntfswipe

When the new option --unused-fast is used, clusters which appear as wiped
are not written again. This is useful for avoiding virtual partitions to
be extended to their full size.

Contributed by michael
edge.strict_endians
Jean-Pierre André 2014-09-02 09:55:53 +02:00
parent c358191f91
commit a7aa91d73d
3 changed files with 134 additions and 4 deletions

View File

@ -77,6 +77,10 @@ because the allocations are always done by full clusters.
Overwrite the space which is currently not allocated to any file (but
may have been used in the past).
.TP
\fB\-U\fR, \fB\-\-unused-fast\fR
Overwrite the space which is currently not allocated to any file, trying
not to overwrite the space not written to since the previous wiping.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Display more debug/warning/error messages.
.TP

View File

@ -169,6 +169,7 @@ static void usage(void)
" -p --pagefile Wipe pagefile (swap space)\n"
" -t --tails Wipe file tails\n"
" -u --unused Wipe unused clusters\n"
" -U --unused-fast Wipe unused clusters (fast)\n"
" -s --undel Wipe undelete data\n"
"\n"
" -a --all Wipe all unused space\n"
@ -262,7 +263,7 @@ static int parse_list(char *list, int **result)
*/
static int parse_options(int argc, char *argv[])
{
static const char *sopt = "-ab:c:dfh?ilmnpqtuvVs";
static const char *sopt = "-ab:c:dfh?ilmnpqtuUvVs";
static struct option lopt[] = {
{ "all", no_argument, NULL, 'a' },
{ "bytes", required_argument, NULL, 'b' },
@ -279,6 +280,7 @@ static int parse_options(int argc, char *argv[])
{ "quiet", no_argument, NULL, 'q' },
{ "tails", no_argument, NULL, 't' },
{ "unused", no_argument, NULL, 'u' },
{ "unused-fast",no_argument, NULL, 'U' },
{ "undel", no_argument, NULL, 's' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
@ -370,6 +372,9 @@ static int parse_options(int argc, char *argv[])
case 'u':
opts.unused++;
break;
case 'U':
opts.unused_fast++;
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
@ -442,7 +447,7 @@ static int parse_options(int argc, char *argv[])
if (!opts.directory && !opts.logfile && !opts.mft &&
!opts.pagefile && !opts.tails && !opts.unused &&
!opts.undel) {
!opts.unused_fast && !opts.undel) {
opts.info = 1;
}
}
@ -511,6 +516,120 @@ free:
return total;
}
/**
* wipe_unused_fast - Faster wipe unused clusters
* @vol: An ntfs volume obtained from ntfs_mount
* @byte: Overwrite with this value
* @act: Wipe, test or info
*
* Read $Bitmap and wipe any clusters that are marked as not in use.
*
* - read/write on a block basis (64 clusters, arbitrary)
* - skip of fully used block
* - skip non-used block already wiped
*
* Return: >0 Success, the attribute was wiped
* 0 Nothing to wipe
* -1 Error, something went wrong
*/
static s64 wipe_unused_fast(ntfs_volume *vol, int byte, enum action act)
{
s64 i;
s64 total = 0;
s64 unused = 0;
s64 result;
u8 *buffer;
u8 *big_buffer;
u32 *u32_buffer;
u32 u32_bytes;
unsigned int blksize;
unsigned int j,k;
BOOL wipe_needed;
if (!vol || (byte < 0))
return -1;
big_buffer = (u8*)malloc(vol->cluster_size*64);
if (!big_buffer) {
ntfs_log_error("malloc failed\n");
return -1;
}
for (i = 0; i < vol->nr_clusters; i+=64) {
blksize = vol->nr_clusters - i;
if (blksize > 64)
blksize = 64;
/* if all clusters in this block are used, ignore the block */
result = 0;
for (j = 0; j < blksize; j++) {
if (utils_cluster_in_use(vol, i+j))
result++;
}
unused += (blksize - result) * vol->cluster_size;
if (result == blksize) {
continue;
}
/*
* if all unused clusters in this block are already wiped,
* ignore the block
*/
if (ntfs_pread(vol->dev, vol->cluster_size * i,
vol->cluster_size * blksize, big_buffer)
!= vol->cluster_size * blksize) {
ntfs_log_error("Read failed at cluster %lld\n",
(long long)i);
goto free;
}
result = 0;
wipe_needed = FALSE;
u32_bytes = (byte & 255)*0x01010101;
buffer = big_buffer;
for (j = 0; (j < blksize) && !wipe_needed; j++) {
u32_buffer = (u32*)buffer;
if (!utils_cluster_in_use(vol, i+j)) {
for (k = 0; (k < vol->cluster_size)
&& (*u32_buffer++ == u32_bytes); k+=4) {
}
if (k < vol->cluster_size)
wipe_needed = TRUE;
}
buffer += vol->cluster_size;
}
if (!wipe_needed) {
continue;
}
/* else wipe unused clusters in the block */
buffer = big_buffer;
for (j = 0; j < blksize; j++) {
if (!utils_cluster_in_use(vol, i+j)) {
memset(buffer, byte, vol->cluster_size);
total += vol->cluster_size;
}
buffer += vol->cluster_size;
}
if ((act == act_wipe)
&& (ntfs_pwrite(vol->dev, vol->cluster_size * i,
vol->cluster_size * blksize, big_buffer)
!= vol->cluster_size * blksize)) {
ntfs_log_error("Write failed at cluster %lld\n",
(long long)i);
goto free;
}
}
ntfs_log_quiet("wipe_unused_fast 0x%02x, %lld bytes"
" already wiped, %lld more bytes wiped\n",
byte, (long long)(unused - total), (long long)total);
free:
free(big_buffer);
return total;
}
/**
* wipe_compressed_attribute - Wipe compressed $DATA attribute
* @vol: An ntfs volume obtained from ntfs_mount
@ -1959,6 +2078,8 @@ static void print_summary(void)
ntfs_log_quiet("%s is about to wipe:\n", EXEC_NAME);
if (opts.unused)
ntfs_log_quiet("\tunused disk space\n");
if (opts.unused_fast)
ntfs_log_quiet("\tunused disk space (fast)\n");
if (opts.tails)
ntfs_log_quiet("\tfile tails\n");
if (opts.mft)
@ -2099,8 +2220,12 @@ int main(int argc, char *argv[])
total += wiped;
}
if (opts.unused) {
wiped = wipe_unused(vol, byte, act);
if (opts.unused || opts.unused_fast) {
if (opts.unused_fast)
wiped = wipe_unused_fast(vol, byte,
act);
else
wiped = wipe_unused(vol, byte, act);
if (wiped < 0)
goto umount;
else

View File

@ -47,6 +47,7 @@ struct options {
int pagefile; /* Wipe pagefile (swap space) */
int tails; /* Wipe file tails */
int unused; /* Wipe unused clusters */
int unused_fast; /* Wipe unused clusters (fast) */
int undel; /* Wipe undelete data */
};