Changes by: flatcap
Update of /cvsroot/linux-ntfs/linux-ntfs/ntfstools
In directory usw-pr-cvs1:/tmp/cvs-serv30120
Modified Files:
Makefile.am Makefile.in
Added Files:
ntfsresize.c
Log Message:
Added Szaka's ntfsresize to the build
--- NEW FILE ---
/**
* ntfsresize - Part of the Linux-NTFS project.
*
* Copyright (c) 2002 Szakacsits Szabolcs
*
* This utility will resize an NTFS volume.
*
* 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 (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include "debug.h"
#include "types.h"
#include "support.h"
#include "endians.h"
#include "bootsect.h"
#include "disk_io.h"
#include "attrib.h"
#include "volume.h"
#include "mft.h"
#include "bitmap.h"
#include "inode.h"
struct {
int verbose;
int debug;
int ro_flag;
s64 size;
char *volume;
} opt;
struct bitmap {
u8 *bm;
s64 size;
};
ntfs_volume *vol = NULL;
struct bitmap lcn_bitmap;
#define rounded_up_division(a, b) (((a) + (b - 1)) / (b))
#define perr_exit(a) err_exit(a ": %s\n", strerror(errno))
int err_exit(const char *fmt, ...) {
va_list ap;
fprintf(stdout, "ERROR: ");
va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
va_end(ap);
fflush(stdout);
fflush(stderr);
exit(1);
}
void usage(char *s) {
printf ("Usage: %s [-nv] [-c clusters] device\n", s);
printf (" -c clusters New NTFS size in clusters\n");
Dprintf(" -d Show debug information\n");
printf (" -v Verbose operation\n");
printf (" -n No write operations (read-only mode)\n");
exit(1);
}
void parse_options(int argc, char **argv) {
char *s;
int i;
memset(&opt, 0, sizeof(opt));
while ((i = getopt(argc, argv, "vdnc:")) != EOF)
switch (i) {
case 'v':
opt.verbose++;
break;
case 'd':
opt.debug = 1;
break;
case 'n':
opt.ro_flag = MS_RDONLY;
break;
case 'c':
opt.size = strtoll(optarg, &s, 0);
if (*s || opt.size < 0 || errno == ERANGE)
err_exit("Size of clusters is out of range\n");
break;
default:
usage(argv[0]);
}
if (optind == argc)
usage(argv[0]);
opt.volume = argv[optind++];
if (optind < argc)
usage(argv[0]);
stderr = stdout;
if (!opt.debug)
if (!(stderr = fopen("/dev/null", "rw")))
perr_exit("Couldn't open /dev/null");
}
s64 nr_clusters_to_bitmap_byte_size(s64 nr_clusters) {
s64 bm_bsize;
bm_bsize = rounded_up_division(nr_clusters, 8);
/* Needs to be multiple of 8 bytes */
bm_bsize = (bm_bsize + 7) & ~7;
Dprintf("Bitmap byte size : %lld (%lld clusters)\n",
bm_bsize, rounded_up_division(bm_bsize, vol->cluster_size));
return bm_bsize;
}
void build_lcn_usage_bitmap(ATTR_RECORD *a) {
run_list *rl;
int i, j;
if (!a->non_resident)
return;
if (!(rl = ntfs_decompress_mapping_pairs(vol, a, NULL)))
perr_exit("ntfs_decompress_mapping_pairs");
for (i = 0; rl[i].length; i++) {
if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
continue;
for (j = 0; j < rl[i].length; j++) {
u64 k = (u64)rl[i].lcn + j;
if (ntfs_get_and_set_bit(lcn_bitmap.bm, k, 1))
err_exit("Cluster %lu "
"referenced multiply times!\n", k);
}
}
free(rl);
}
void walk_attributes(MFT_RECORD *mr) {
ntfs_attr_search_ctx *ctx;
if (!(ctx = ntfs_get_attr_search_ctx(NULL, mr)))
perr_exit("ntfs_get_attr_search_ctx");
while (!ntfs_walk_attrs(ctx)) {
if (ctx->attr->type == AT_END)
break;
build_lcn_usage_bitmap(ctx->attr);
}
ntfs_put_attr_search_ctx(ctx);
}
void get_bitmap_data(ntfs_volume *vol, struct bitmap *bm) {
ntfs_inode *ni;
ntfs_attr_search_ctx *ctx;
if (!(ni = ntfs_open_inode(vol, (MFT_REF)FILE_Bitmap)))
perr_exit("ntfs_open_inode");
if (!(ctx = ntfs_get_attr_search_ctx(ni, NULL)))
perr_exit("ntfs_get_attr_search_ctx");
if (ntfs_lookup_attr(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx))
perr_exit("ntfs_lookup_attr");
bm->size = get_attribute_value_length(ctx->attr);
if (!(bm->bm = (u8 *)malloc(bm->size)))
perr_exit("get_bitmap_data");
if (get_attribute_value(vol, ni->mrec, ctx->attr, bm->bm) != bm->size)
perr_exit("Couldn't get $Bitmap $DATA\n");
ntfs_put_attr_search_ctx(ctx);
ntfs_close_inode(ni);
}
void compare_bitmaps(struct bitmap *a, struct bitmap *b) {
int i;
if (a->size != b->size)
err_exit("$Bitmap file size doesn't match "
"calculated size ((%d != %d)\n", a->size, b->size);
for (i = 0; i < a->size; i++)
if (a->bm[i] != b->bm[i])
err_exit("Cluster bitmaps differ at %d (%d != %d)\n",
i, a->bm[i], b->bm[i]);
}
void walk_inodes() {
s32 inode;
MFT_REF mref;
MFT_RECORD *mrec = NULL;
for (inode = 0; inode < vol->nr_mft_records; inode++) {
mref = (MFT_REF)inode;
if (ntfs_read_file_record(vol, mref, &mrec, NULL))
perr_exit("ntfs_read_file_record");
if (!(mrec->flags & MFT_RECORD_IN_USE))
continue;
walk_attributes(mrec);
}
if (mrec)
free(mrec);
}
void advise_on_resize() {
u64 i;
printf("ERROR: Fragmented volume not yet supported. "
"Try to defragment it before resize.\n");
for (i = vol->nr_clusters - 1; i > 0; i--)
if (ntfs_get_bit(lcn_bitmap.bm, i))
break;
if (++i >= vol->nr_clusters)
exit(1);
err_exit("However, you could resize at cluster %lld gaining %lld MB.\n",
i, ((vol->nr_clusters - i) * vol->cluster_size) >> 20);
}
void look_for_bad_sector(ATTR_RECORD *a) {
run_list *rl;
int i;
rl = ntfs_decompress_mapping_pairs(vol, a, NULL);
if (!rl)
perr_exit("ntfs_decompress_mapping_pairs");
for (i = 0; rl[i].length; i++)
if (rl[i].lcn != LCN_HOLE)
err_exit("Volume has bad sectors, not supported\n");
free(rl);
}
void rl_set(run_list *rl, VCN vcn, LCN lcn, s64 len) {
rl->vcn = vcn;
rl->lcn = lcn;
rl->length = len;
}
/*
* $Bitmap can overlap the end of the volume. Any bits in this region
* must be set. This region also encompasses the backup boot sector.
*/
void bitmap_file_data_fixup(s64 clusters, struct bitmap *bm) {
s64 i;
for (i = clusters; i < bm->size << 3; i++)
ntfs_set_bit(bm->bm, (u64)i, 1);
}
/*
* FIXME: this function should go away and instead using a generalized
* "truncate_bitmap_unnamed_attr()"
*/
void truncate_badclust_bad_attr(ATTR_RECORD *a, s64 nr_clusters) {
run_list *rl_bad;
int mp_size;
char *mp;
if (!a->non_resident)
/* FIXME: handle resident attribute value */
perr_exit("Resident attribute in $BadClust not supported!");
if (!(rl_bad = (run_list *)malloc(2 * sizeof(run_list))))
perr_exit("Couldn't get memory");
rl_set(rl_bad, 0LL, (LCN)LCN_HOLE, nr_clusters);
rl_set(rl_bad + 1, nr_clusters, -1LL, 0LL);
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl_bad);
if (!(mp = (char *)calloc(1, mp_size)))
perr_exit("Couldn't get memory");
if (ntfs_build_mapping_pairs(vol, mp, mp_size, rl_bad))
exit(1);
memcpy((char *)a + a->mapping_pairs_offset, mp, mp_size);
a->highest_vcn = cpu_to_le64(nr_clusters - 1LL);
a->allocated_size = cpu_to_le64(nr_clusters * vol->cluster_size);
a->data_size = cpu_to_le64(nr_clusters * vol->cluster_size);
free(rl_bad);
free(mp);
}
void truncate_bitmap_unnamed_attr(ATTR_RECORD *a, s64 nr_clusters) {
run_list *rl;
s64 bm_bsize, size;
s64 nr_bm_clusters;
int i, j, mp_size;
int trunc_at = -1; /* FIXME: -1 means unset */
char *mp;
if (!a->non_resident)
/* FIXME: handle resident attribute value */
perr_exit("Resident data attribute in $Bitmap not supported!");
bm_bsize = nr_clusters_to_bitmap_byte_size(nr_clusters);
nr_bm_clusters = rounded_up_division(bm_bsize, vol->cluster_size);
if (!(rl = ntfs_decompress_mapping_pairs(vol, a, NULL)))
perr_exit("ntfs_decompress_mapping_pairs");
/* Unallocate truncated clusters in $Bitmap */
for (i = 0; rl[i].length; i++) {
if (rl[i].vcn + rl[i].length <= nr_bm_clusters)
continue;
if (trunc_at == -1)
trunc_at = i;
if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
continue;
for (j = 0; j < rl[i].length; j++)
if (rl[i].vcn + j >= nr_bm_clusters) {
u64 k = (u64)rl[i].lcn + j;
ntfs_set_bit(lcn_bitmap.bm, k, 0);
printf("Unallocate cluster "
"%llu (%llx)\n", k, k);
}
}
/* FIXME: realloc lcn_bitmap.bm (if it's worth the risk) */
lcn_bitmap.size = bm_bsize;
bitmap_file_data_fixup(nr_clusters, &lcn_bitmap);
if (trunc_at != -1) {
/* NOTE: 'i' always > 0 */
i = nr_bm_clusters - rl[trunc_at].vcn;
rl[trunc_at].length = i;
rl_set(rl + trunc_at + 1, nr_bm_clusters, -1LL, 0LL);
printf("Runlist truncated at index %d, "
"new cluster length %d\n", trunc_at, i);
}
if (!opt.ro_flag) {
size = ntfs_rl_pwrite(vol, rl, 0, bm_bsize, lcn_bitmap.bm);
if (bm_bsize != size) {
if (size == -1)
perr_exit("Couldn't write $Bitmap");
printf("Couldn't write full $Bitmap file "
"(%lld from %lld)\n", size, bm_bsize);
exit(1);
}
}
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl);
if (!(mp = (char *)calloc(1, mp_size)))
perr_exit("Couldn't get memory");
if (ntfs_build_mapping_pairs(vol, mp, mp_size, rl))
exit(1);
memcpy((char *)a + a->mapping_pairs_offset, mp, mp_size);
a->highest_vcn = cpu_to_le64(nr_bm_clusters - 1LL);
a->allocated_size = cpu_to_le64(nr_bm_clusters * vol->cluster_size);
a->data_size = cpu_to_le64(bm_bsize);
a->initialized_size = cpu_to_le64(bm_bsize);
free(rl);
free(mp);
}
void lookup_data_attr(MFT_REF mref, char *aname, ntfs_attr_search_ctx **ctx) {
ntfs_inode *ni;
uchar_t *ustr = NULL;
int len = 0;
if (!(ni = ntfs_open_inode(vol, mref)))
perr_exit("ntfs_open_inode");
if (!(*ctx = ntfs_get_attr_search_ctx(ni, NULL)))
perr_exit("ntfs_get_attr_search_ctx");
if (aname && ((len = ntfs_mbstoucs(aname, &ustr, 0)) == -1))
perr_exit("Unable to convert string to Unicode");
if (ntfs_lookup_attr(AT_DATA, ustr, len, 0, 0, NULL, 0, *ctx))
perr_exit("ntfs_lookup_attr");
free(ustr);
}
int write_mft_record(ntfs_attr_search_ctx *ctx) {
if (opt.ro_flag)
return 0;
return ntfs_write_mft_record(vol, ctx->ntfs_ino->mft_no, ctx->mrec);
}
void truncate_badclust_file(s64 nr_clusters) {
ntfs_attr_search_ctx *ctx = NULL;
lookup_data_attr((MFT_REF)FILE_BadClus, "$Bad", &ctx);
look_for_bad_sector(ctx->attr);
/* FIXME: sanity_check_attr(ctx->attr); */
/* FIXME: should use an "extended" truncate_bitmap_unnamed_attr() */
truncate_badclust_bad_attr(ctx->attr, nr_clusters);
if (write_mft_record(ctx))
perr_exit("Couldn't update $BadClust");
/* FIXME: clean up API => ntfs_put_attr_search_ctx() also closes ni */
ntfs_put_attr_search_ctx(ctx);
}
void truncate_bitmap_file(s64 nr_clusters) {
ntfs_attr_search_ctx *ctx = NULL;
lookup_data_attr((MFT_REF)FILE_Bitmap, NULL, &ctx);
/* FIXME: sanity_check_attr(ctx->attr); */
truncate_bitmap_unnamed_attr(ctx->attr, nr_clusters);
if (write_mft_record(ctx))
perr_exit("Couldn't update $Bitmap");
ntfs_put_attr_search_ctx(ctx);
}
void setup_lcn_bitmap() {
/* Determine lcn bitmap byte size and allocate it. */
lcn_bitmap.size = nr_clusters_to_bitmap_byte_size(vol->nr_clusters);
if (!(lcn_bitmap.bm = (unsigned char *)calloc(1, lcn_bitmap.size)))
perr_exit("Failed to allocate internal buffer");
bitmap_file_data_fixup(vol->nr_clusters, &lcn_bitmap);
}
/* FIXME: should be done using ntfs_* functions */
void update_bootsector(s64 nr_clusters) {
NTFS_BOOT_SECTOR bs;
if (lseek(vol->fd, 0, SEEK_SET) == (off_t)-1)
perr_exit("lseek");
if (read(vol->fd, &bs, sizeof(NTFS_BOOT_SECTOR)) == -1)
perr_exit("read() error");
bs.number_of_sectors = nr_clusters * bs.bpb.sectors_per_cluster;
bs.number_of_sectors = cpu_to_le64(bs.number_of_sectors);
if (lseek(vol->fd, 0, SEEK_SET) == (off_t)-1)
perr_exit("lseek");
if (!opt.ro_flag)
if (write(vol->fd, &bs, sizeof(NTFS_BOOT_SECTOR)) == -1)
perr_exit("write() error");
}
int main(int argc, char **argv)
{
struct bitmap on_disk_lcn_bitmap;
int i;
parse_options(argc, argv);
if (!(vol = ntfs_mount(opt.volume, opt.ro_flag)))
perr_exit("ntfs_mount failed");
setup_lcn_bitmap();
walk_inodes();
get_bitmap_data(vol, &on_disk_lcn_bitmap);
compare_bitmaps(&on_disk_lcn_bitmap, &lcn_bitmap);
free(on_disk_lcn_bitmap.bm);
printf("Number of clusters: %lld\n", vol->nr_clusters);
printf("Cluster size : %u\n", vol->cluster_size);
/* FIXME: check/adjust opt.size validity */
if (opt.size > vol->nr_clusters)
err_exit("Volume enlargement not yet supported\n");
else if (opt.size == vol->nr_clusters)
exit(0); /* FIXME: backup boot sector not counted! */
for (i = opt.size; i < vol->nr_clusters; i++)
if (ntfs_get_bit(lcn_bitmap.bm, (u64)i))
/* FIXME: relocate cluster */
advise_on_resize();
/* FIXME: first do all checks before any write attempt */
truncate_badclust_file(opt.size);
truncate_bitmap_file(opt.size);
update_bootsector(opt.size);
/* FIXME: create backup boot sector -- if possible*/
/* FIXME: "call" ntfsfix: set the volume dirty, delete log, etc */
return 0;
}
Index: Makefile.am
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/Makefile.am,v
retrieving revision 1.26
retrieving revision 1.27
diff -U2 -r1.26 -r1.27
--- Makefile.am 3 Jul 2002 14:38:40 -0000 1.26
+++ Makefile.am 8 Jul 2002 15:59:34 -0000 1.27
@@ -8,5 +8,5 @@
bin_PROGRAMS = ntfsfix ntfsinfo
sbin_PROGRAMS = mkntfs ntfslabel
-EXTRA_PROGRAMS = ntfsundelete ntfsdump_logfile dumplog
+EXTRA_PROGRAMS = ntfsundelete ntfsresize ntfsdump_logfile dumplog
man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8
@@ -36,10 +36,13 @@
ntfsinfo_LDFLAGS = $(all_libraries)
-# We don't distribute these as they are not really of any use to anyone except
-# us developers for playing with.
+# We don't distribute these
ntfsundelete_SOURCES = ntfsundelete.c
ntfsundelete_LDADD = $(top_srcdir)/libntfs/libntfs.la
ntfsundelete_LDFLAGS = $(all_libraries)
+
+ntfsresize_SOURCES = ntfsresize.c
+ntfsresize_LDADD = $(top_srcdir)/libntfs/libntfs.la
+ntfsresize_LDFLAGS = $(all_libraries)
ntfsdump_logfile_SOURCES= ntfsdump_logfile.c
Index: Makefile.in
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/Makefile.in,v
retrieving revision 1.32
retrieving revision 1.33
diff -U2 -r1.32 -r1.33
--- Makefile.in 3 Jul 2002 14:38:40 -0000 1.32
+++ Makefile.in 8 Jul 2002 15:59:34 -0000 1.33
@@ -94,5 +94,5 @@
bin_PROGRAMS = ntfsfix ntfsinfo
sbin_PROGRAMS = mkntfs ntfslabel
-EXTRA_PROGRAMS = ntfsundelete ntfsdump_logfile dumplog
+EXTRA_PROGRAMS = ntfsundelete ntfsresize ntfsdump_logfile dumplog
man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8
@@ -122,6 +122,5 @@
ntfsinfo_LDFLAGS = $(all_libraries)
-# We don't distribute these as they are not really of any use to anyone except
-# us developers for playing with.
+# We don't distribute these
ntfsundelete_SOURCES = ntfsundelete.c
@@ -129,4 +128,8 @@
ntfsundelete_LDFLAGS = $(all_libraries)
+ntfsresize_SOURCES = ntfsresize.c
+ntfsresize_LDADD = $(top_srcdir)/libntfs/libntfs.la
+ntfsresize_LDFLAGS = $(all_libraries)
+
ntfsdump_logfile_SOURCES = ntfsdump_logfile.c
ntfsdump_logfile_LDADD = $(top_srcdir)/libntfs/libntfs.la
@@ -149,4 +152,6 @@
ntfsundelete_OBJECTS = ntfsundelete.$(OBJEXT)
ntfsundelete_DEPENDENCIES = $(top_srcdir)/libntfs/libntfs.la
+ntfsresize_OBJECTS = ntfsresize.$(OBJEXT)
+ntfsresize_DEPENDENCIES = $(top_srcdir)/libntfs/libntfs.la
ntfsdump_logfile_OBJECTS = ntfsdump_logfile.$(OBJEXT)
ntfsdump_logfile_DEPENDENCIES = $(top_srcdir)/libntfs/libntfs.la
@@ -180,7 +185,8 @@
DEP_FILES = .deps/attrdef.P .deps/boot.P .deps/dumplog.P .deps/mkntfs.P \
.deps/ntfsdump_logfile.P .deps/ntfsfix.P .deps/ntfsinfo.P \
-.deps/ntfslabel.P .deps/ntfsundelete.P .deps/sd.P .deps/upcase.P
-SOURCES = $(ntfsundelete_SOURCES) $(ntfsdump_logfile_SOURCES) $(dumplog_SOURCES) $(ntfsfix_SOURCES) $(ntfsinfo_SOURCES) $(mkntfs_SOURCES) $(ntfslabel_SOURCES)
-OBJECTS = $(ntfsundelete_OBJECTS) $(ntfsdump_logfile_OBJECTS) $(dumplog_OBJECTS) $(ntfsfix_OBJECTS) $(ntfsinfo_OBJECTS) $(mkntfs_OBJECTS) $(ntfslabel_OBJECTS)
+.deps/ntfslabel.P .deps/ntfsresize.P .deps/ntfsundelete.P .deps/sd.P \
+.deps/upcase.P
+SOURCES = $(ntfsundelete_SOURCES) $(ntfsresize_SOURCES) $(ntfsdump_logfile_SOURCES) $(dumplog_SOURCES) $(ntfsfix_SOURCES) $(ntfsinfo_SOURCES) $(mkntfs_SOURCES) $(ntfslabel_SOURCES)
+OBJECTS = $(ntfsundelete_OBJECTS) $(ntfsresize_OBJECTS) $(ntfsdump_logfile_OBJECTS) $(dumplog_OBJECTS) $(ntfsfix_OBJECTS) $(ntfsinfo_OBJECTS) $(mkntfs_OBJECTS) $(ntfslabel_OBJECTS)
all: all-redirect
@@ -296,4 +302,8 @@
@rm -f ntfsundelete$(EXEEXT)
$(LINK) $(ntfsundelete_LDFLAGS) $(ntfsundelete_OBJECTS) $(ntfsundelete_LDADD) $(LIBS)
+
+ntfsresize$(EXEEXT): $(ntfsresize_OBJECTS) $(ntfsresize_DEPENDENCIES)
+ @rm -f ntfsresize$(EXEEXT)
+ $(LINK) $(ntfsresize_LDFLAGS) $(ntfsresize_OBJECTS) $(ntfsresize_LDADD) $(LIBS)
ntfsdump_logfile$(EXEEXT): $(ntfsdump_logfile_OBJECTS) $(ntfsdump_logfile_DEPENDENCIES)
|