ntfscmp.c revision 7e7bd3dccbfe8f79e25e5c1554b5bc3a9aaca321
/**
* ntfscmp - Part of the Linux-NTFS project.
*
* Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2007 Yura Pakhuchiy
*
* This utility compare two NTFS volumes.
*
* 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 "utils.h"
#include "mst.h"
#include "version.h"
#include "support.h"
static const char *EXEC_NAME = "ntfscmp";
static const char *invalid_ntfs_msg =
"Apparently device '%s' doesn't have a valid NTFS.\n"
"Maybe you selected the wrong partition? Or the whole disk instead of a\n"
static const char *corrupt_volume_msg =
"Apparently you have a corrupted NTFS. Please run the filesystem checker\n"
"on Windows by invoking chkdsk /f. Don't forget the /f (force) parameter,\n"
"it's important! You probably also need to reboot Windows to take effect.\n";
static const char *hibernated_volume_msg =
"Apparently the NTFS partition is hibernated. Windows must be resumed and\n"
"turned off properly\n";
static struct {
int debug;
int show_progress;
int verbose;
char *vol1;
char *vol2;
} opt;
#define NTFS_PROGBAR 0x0001
#define NTFS_PROGBAR_SUPPRESS 0x0002
struct progress_bar {
int resolution;
int flags;
float unit;
};
/* WARNING: don't modify the text, external tools grep for it */
#define ERR_PREFIX "ERROR"
{
if (newline)
}
static void err_printf(const char *fmt, ...)
{
}
/**
* err_exit
*
* Print and error message and exit the program.
*/
{
exit(1);
}
/**
* perr_exit
*
* Print and error message and exit the program
*/
{
exit(1);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
static void usage(void)
{
printf("\nUsage: %s [OPTIONS] DEVICE1 DEVICE2\n"
" Compare two NTFS volumes and tell the differences.\n"
"\n"
" -P, --no-progress-bar Don't show progress bar\n"
" -v, --verbose More output\n"
" -h, --help Display this help\n"
#ifdef DEBUG
" -d, --debug Show debug information\n"
#endif
"\n", EXEC_NAME);
exit(1);
}
{
static const char *sopt = "-dhPv";
#ifdef DEBUG
#endif
};
int c;
switch (c) {
case 1: /* A non-option argument */
} else {
err_printf("Too many arguments!\n");
usage();
}
break;
#ifdef DEBUG
case 'd':
break;
#endif
case 'h':
case '?':
usage();
case 'P':
opt.show_progress = 0;
break;
case 'v':
break;
default:
usage();
break;
}
}
err_printf("You must specify exactly 2 volumes.\n");
usage();
}
/* Redirect stderr to stdout, note fflush()es are essential! */
perror("Failed to redirect stderr to stdout");
exit(1);
}
#ifdef DEBUG
#endif
}
{
perr_println("ntfs_attr_get_search_ctx");
return ret;
}
{
p->resolution = 100;
}
{
float percent;
if (!(p->flags & NTFS_PROGBAR))
return;
if (p->flags & NTFS_PROGBAR_SUPPRESS)
return;
/* WARNING: don't modify the texts, external tools grep for them */
return;
} else
printf("100.00 percent completed\n");
}
{
if (ni->nr_extents >= 0)
}
{
return 0;
if (ntfs_inode_close(ni)) {
return -1;
}
return 0;
}
{
}
#define NTFSCMP_OK 0
#define NTFSCMP_INODE_OPEN_ERROR 1
#define NTFSCMP_INODE_OPEN_IO_ERROR 2
#define NTFSCMP_INODE_OPEN_ENOENT_ERROR 3
#define NTFSCMP_EXTENSION_RECORD 4
#define NTFSCMP_INODE_CLOSE_ERROR 5
static const char *ntfscmp_errs[] = {
"OK",
"INODE_OPEN_ERROR",
"INODE_OPEN_IO_ERROR",
"INODE_OPEN_ENOENT_ERROR",
"EXTENSION_RECORD",
"INODE_CLOSE_ERROR",
""
};
static const char *err2string(int err)
{
return ntfscmp_errs[err];
}
static const char *pret2str(void *p)
{
if (p == NULL)
return "FAILED";
return "OK";
}
{
return NTFSCMP_INODE_OPEN_IO_ERROR;
return NTFSCMP_INODE_OPEN_ENOENT_ERROR;
return NTFSCMP_INODE_OPEN_ERROR;
}
if (inode_close(*ni) != 0)
return NTFSCMP_INODE_CLOSE_ERROR;
return NTFSCMP_EXTENSION_RECORD;
}
return NTFSCMP_OK;
}
{
if (ctx->base_ntfs_ino)
return ctx->base_ntfs_ino;
}
{
}
{
}
{
}
static void print_attribute_name(char *name)
{
if (name)
}
#define GET_ATTR_NAME(a) \
((a)->name_length)
{
if (*name) {
}
}
const int uname_len)
{
int name_len;
return NULL;
if (name_len < 0) {
perr_print("ntfs_ucstombs");
puts("");
exit(1);
} else if (name_len > 0)
return name;
return NULL;
}
{
}
{
}
{
printf(" ");
}
{
}
{
}
{
}
{
printf("content: DIFFER\n");
}
{
return -1;
}
return 0;
}
struct cmp_ia {
};
{
perr_println("Failed to readall BITMAP");
return -1;
}
goto free_bm;
perr_println("Failed to pread INDEX_ALLOCATION");
goto free_ia;
}
return 0;
return -1;
}
{
return;
return;
/*
* FIXME: ia can be the same even if the bitmap sizes are different.
*/
goto out;
goto out;
goto out;
bit = 0;
goto out;
}
if (ret1 == -1)
continue;
goto out;
}
bit++;
if (bit > 7) {
bit = 0;
}
}
out:
return;
}
{
printf("abrupt length: %lld != %lld ",
puts("");
return;
}
if (count1 == -1) {
exit(1);
}
if (count1 == 0) {
return; /* we are ready */
exit(1);
}
return;
}
err_printf("(len = %lld, pos = %lld, count = %lld)\n",
exit(1);
}
{
return 1;
if (a1->non_resident) {
/*
* FIXME: includes paddings which are not handled by ntfsinfo!
*/
}
}
{
printf("header: DIFFER\n");
}
goto close_attribs;
}
goto close_attribs;
goto close_attribs;
}
/*
* If difference exists then it's already reported at the
* attribute header since the mapping pairs must differ.
*/
return;
}
else
}
{
return;
if (name)
printf(" ");
}
char *name1,
char *name2)
{
return;
printf("\n");
}
{
int ret = 0;
ret = 1;
ret = 1;
return ret;
}
char *prev_name)
{
if (!prev_atype && !prev_name)
return 1;
return 1;
return 1;
return 1;
printf("record %llu lowest_vcn %lld: SKIPPED\n",
}
return 0;
}
{
if (name) {
if (!*prev_name)
perr_exit("strdup error");
}
*prev_atype = atype;
}
{
}
int *err)
{
int ret;
if (ret) {
} else
return ret;
}
{
int ret = -1;
return -1;
goto out;
while (1) {
old_atype1 = atype1;
ret2))
old_ret1))
printf("attribute walk (errno): %d != %d\n",
}
break;
}
printf("presence: EXISTS != MISSING\n");
atype1);
}
printf("presence: MISSING != EXISTS \n");
}
} else /* atype1 == atype2 */ {
}
}
}
ret = 0;
out:
return ret;
}
{
struct progress_bar progress;
int pb_flags = 0; /* progress bar flags */
if (opt.show_progress)
pb_flags |= NTFS_PROGBAR;
if (nr_mft_records != nr_mft_records2) {
printf("Number of mft records: %lld != %lld\n",
if (nr_mft_records > nr_mft_records2)
}
progress_update(&progress, 0);
printf("open: %s != %s\n",
goto close_inodes;
}
if (ret1 != NTFSCMP_OK)
goto close_inodes;
return -1;
}
if (inode_close(ni1) != 0)
return -1;
if (inode_close(ni2) != 0)
return -1;
}
return 0;
}
{
unsigned long mntflag;
"continue. You might try\nan another Linux distro.\n");
exit(1);
}
if (mntflag & NTFS_MF_MOUNTED) {
if (!(mntflag & NTFS_MF_READONLY))
err_exit("Device '%s' is mounted read-write. "
"You must 'umount' it first.\n", volume);
}
exit(1);
}
return vol;
}
{
exit(1);
exit(0);
}