summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ntfsprogs/ntfscmp.c
diff options
context:
space:
mode:
authorKeith M Wesolowski <wesolows@foobazco.org>2014-08-20 20:04:47 +0000
committerKeith M Wesolowski <wesolows@foobazco.org>2014-08-20 20:04:47 +0000
commit5f00496ef2e39b976b062f196ff01a99fd4864a4 (patch)
tree20be9cbc8f4b7ed3e616ce23552728083801e846 /usr/src/cmd/ntfsprogs/ntfscmp.c
parentaf59b1a40df03681c1c8129aea7b1f5f52f2bcea (diff)
parent86bb58aec7165f8a0303564575c65e5a2ad58bf1 (diff)
downloadillumos-joyent-release-20140821.tar.gz
[illumos-gate merge]20140821release-20140821
commit 86bb58aec7165f8a0303564575c65e5a2ad58bf1 5095 panic when adding a duplicate dbuf to dn_dbufs commit 60a61f7adabc73a7a0cb70d200ac2a6735f4a6e8 5092 env files don't need to define LOCKNAME by default 5091 illumos.sh env file's LOCKNAME definition is busted commit 5e3f545c431ec4bce3e1b52f3f81bc9befe501f2 4989 removal of ntfsprogs and parted commit ba3594ba9b5dd4c846c472a8d657edcb7c8109ac 5066 remove support for non-ANSI compilation 5068 Remove SCCSID() macro from <macros.h> commit d8ccf998f9c944b8cf27ed840c376f9b79ebce5c 5087 8-bit inline atomic {add,or,and} use wrong reg constraints on x86 Manifests: usr/src/pkg/manifests/SUNWntfsprogs.mf (torch library) usr/src/pkg/manifests/SUNWparted.mf (torch headers) usr/src/pkg/manifests/system-file-system-ntfsprogs.mf usr/src/pkg/manifests/system-storage-parted.mf
Diffstat (limited to 'usr/src/cmd/ntfsprogs/ntfscmp.c')
-rw-r--r--usr/src/cmd/ntfsprogs/ntfscmp.c1005
1 files changed, 0 insertions, 1005 deletions
diff --git a/usr/src/cmd/ntfsprogs/ntfscmp.c b/usr/src/cmd/ntfsprogs/ntfscmp.c
deleted file mode 100644
index d247c259b0..0000000000
--- a/usr/src/cmd/ntfsprogs/ntfscmp.c
+++ /dev/null
@@ -1,1005 +0,0 @@
-/**
- * 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.
- *
- * 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 "compat.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"
-"partition (e.g. /dev/hda, not /dev/hda1)?\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 {
- u64 start;
- u64 stop;
- int resolution;
- int flags;
- float unit;
-};
-
-/* WARNING: don't modify the text, external tools grep for it */
-#define ERR_PREFIX "ERROR"
-#define PERR_PREFIX ERR_PREFIX "(%d): "
-#define NERR_PREFIX ERR_PREFIX ": "
-
-__attribute__((format(printf, 2, 3)))
-static void perr_printf(int newline, const char *fmt, ...)
-{
- va_list ap;
- int eo = errno;
-
- fprintf(stdout, PERR_PREFIX, eo);
- va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
- va_end(ap);
- fprintf(stdout, ": %s", strerror(eo));
- if (newline)
- fprintf(stdout, "\n");
- fflush(stdout);
- fflush(stderr);
-}
-
-#define perr_print(...) perr_printf(0, __VA_ARGS__)
-#define perr_println(...) perr_printf(1, __VA_ARGS__)
-
-__attribute__((format(printf, 1, 2)))
-static void err_printf(const char *fmt, ...)
-{
- va_list ap;
-
- fprintf(stdout, NERR_PREFIX);
- va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
- va_end(ap);
- fflush(stdout);
- fflush(stderr);
-}
-
-/**
- * err_exit
- *
- * Print and error message and exit the program.
- */
-__attribute__((noreturn))
-__attribute__((format(printf, 1, 2)))
-static int err_exit(const char *fmt, ...)
-{
- va_list ap;
-
- fprintf(stdout, NERR_PREFIX);
- va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
- va_end(ap);
- fflush(stdout);
- fflush(stderr);
- exit(1);
-}
-
-/**
- * perr_exit
- *
- * Print and error message and exit the program
- */
-__attribute__((noreturn))
-__attribute__((format(printf, 1, 2)))
-static int perr_exit(const char *fmt, ...)
-{
- va_list ap;
- int eo = errno;
-
- fprintf(stdout, PERR_PREFIX, eo);
- va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
- va_end(ap);
- printf(": %s\n", strerror(eo));
- fflush(stdout);
- fflush(stderr);
- 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
- */
-__attribute__((noreturn))
-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);
- printf("%s%s", ntfs_bugs, ntfs_home);
- exit(1);
-}
-
-
-static void parse_options(int argc, char **argv)
-{
- static const char *sopt = "-dhPv";
- static const struct option lopt[] = {
-#ifdef DEBUG
- { "debug", no_argument, NULL, 'd' },
-#endif
- { "help", no_argument, NULL, 'h' },
- { "no-progress-bar", no_argument, NULL, 'P' },
- { "verbose", no_argument, NULL, 'v' },
- { NULL, 0, NULL, 0 }
- };
-
- int c;
-
- memset(&opt, 0, sizeof(opt));
- opt.show_progress = 1;
-
- while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
- switch (c) {
- case 1: /* A non-option argument */
- if (!opt.vol1) {
- opt.vol1 = argv[optind - 1];
- } else if (!opt.vol2) {
- opt.vol2 = argv[optind - 1];
- } else {
- err_printf("Too many arguments!\n");
- usage();
- }
- break;
-#ifdef DEBUG
- case 'd':
- opt.debug++;
- break;
-#endif
- case 'h':
- case '?':
- usage();
- case 'P':
- opt.show_progress = 0;
- break;
- case 'v':
- opt.verbose++;
- break;
- default:
- err_printf("Unknown option '%s'.\n", argv[optind - 1]);
- usage();
- break;
- }
- }
-
- if (opt.vol1 == NULL || opt.vol2 == NULL) {
- err_printf("You must specify exactly 2 volumes.\n");
- usage();
- }
-
- /* Redirect stderr to stdout, note fflush()es are essential! */
- fflush(stdout);
- fflush(stderr);
- if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) {
- perror("Failed to redirect stderr to stdout");
- exit(1);
- }
- fflush(stdout);
- fflush(stderr);
-
-#ifdef DEBUG
- if (!opt.debug)
- if (!freopen("/dev/null", "w", stderr))
- perr_exit("Failed to redirect stderr to /dev/null");
-#endif
-}
-
-static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni)
-{
- ntfs_attr_search_ctx *ret;
-
- if ((ret = ntfs_attr_get_search_ctx(ni, NULL)) == NULL)
- perr_println("ntfs_attr_get_search_ctx");
-
- return ret;
-}
-
-static void progress_init(struct progress_bar *p, u64 start, u64 stop, int flags)
-{
- p->start = start;
- p->stop = stop;
- p->unit = 100.0 / (stop - start);
- p->resolution = 100;
- p->flags = flags;
-}
-
-static void progress_update(struct progress_bar *p, u64 current)
-{
- 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 */
- percent = p->unit * current;
- if (current != p->stop) {
- if ((current - p->start) % p->resolution)
- return;
- printf("%6.2f percent completed\r", percent);
- } else
- printf("100.00 percent completed\n");
- fflush(stdout);
-}
-
-static u64 inumber(ntfs_inode *ni)
-{
- if (ni->nr_extents >= 0)
- return ni->mft_no;
-
- return ni->u.base_ni->mft_no;
-}
-
-static int inode_close(ntfs_inode *ni)
-{
- if (ni == NULL)
- return 0;
-
- if (ntfs_inode_close(ni)) {
- perr_println("ntfs_inode_close: inode %llu", inumber(ni));
- return -1;
- }
- return 0;
-}
-
-static inline s64 get_nr_mft_records(ntfs_volume *vol)
-{
- return vol->mft_na->initialized_size >> vol->mft_record_size_bits;
-}
-
-#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";
-}
-
-static int inode_open(ntfs_volume *vol, MFT_REF mref, ntfs_inode **ni)
-{
- *ni = ntfs_inode_open(vol, mref);
- if (*ni == NULL) {
- if (errno == EIO)
- return NTFSCMP_INODE_OPEN_IO_ERROR;
- if (errno == ENOENT)
- return NTFSCMP_INODE_OPEN_ENOENT_ERROR;
-
- perr_println("Reading inode %lld failed", mref);
- return NTFSCMP_INODE_OPEN_ERROR;
- }
-
- if ((*ni)->mrec->base_mft_record) {
-
- if (inode_close(*ni) != 0)
- return NTFSCMP_INODE_CLOSE_ERROR;
-
- return NTFSCMP_EXTENSION_RECORD;
- }
-
- return NTFSCMP_OK;
-}
-
-static ntfs_inode *base_inode(ntfs_attr_search_ctx *ctx)
-{
- if (ctx->base_ntfs_ino)
- return ctx->base_ntfs_ino;
-
- return ctx->ntfs_ino;
-}
-
-static void print_inode(u64 inum)
-{
- printf("Inode %llu ", inum);
-}
-
-static void print_inode_ni(ntfs_inode *ni)
-{
- print_inode(inumber(ni));
-}
-
-static void print_attribute_type(ATTR_TYPES atype)
-{
- printf("attribute 0x%x", atype);
-}
-
-static void print_attribute_name(char *name)
-{
- if (name)
- printf(":%s", name);
-}
-
-#define GET_ATTR_NAME(a) \
- ((ntfschar *)(((u8 *)(a)) + le16_to_cpu((a)->name_offset))), \
- ((a)->name_length)
-
-static void free_name(char **name)
-{
- if (*name) {
- free(*name);
- *name = NULL;
- }
-}
-
-static char *get_attr_name(u64 mft_no,
- ATTR_TYPES atype,
- const ntfschar *uname,
- const int uname_len)
-{
- char *name = NULL;
- int name_len;
-
- if (atype == AT_END)
- return NULL;
-
- name_len = ntfs_ucstombs(uname, uname_len, &name, 0);
- if (name_len < 0) {
- perr_print("ntfs_ucstombs");
- print_inode(mft_no);
- print_attribute_type(atype);
- puts("");
- exit(1);
-
- } else if (name_len > 0)
- return name;
-
- free_name(&name);
- return NULL;
-}
-
-static char *get_attr_name_na(ntfs_attr *na)
-{
- return get_attr_name(inumber(na->ni), na->type, na->name, na->name_len);
-}
-
-static char *get_attr_name_ctx(ntfs_attr_search_ctx *ctx)
-{
- u64 mft_no = inumber(ctx->ntfs_ino);
- ATTR_TYPES atype = ctx->attr->type;
-
- return get_attr_name(mft_no, atype, GET_ATTR_NAME(ctx->attr));
-}
-
-static void print_attribute(ATTR_TYPES atype, char *name)
-{
- print_attribute_type(atype);
- print_attribute_name(name);
- printf(" ");
-}
-
-static void print_na(ntfs_attr *na)
-{
- char *name = get_attr_name_na(na);
- print_inode_ni(na->ni);
- print_attribute(na->type, name);
- free_name(&name);
-}
-
-static void print_attribute_ctx(ntfs_attr_search_ctx *ctx)
-{
- char *name = get_attr_name_ctx(ctx);
- print_attribute(ctx->attr->type, name);
- free_name(&name);
-}
-
-static void print_ctx(ntfs_attr_search_ctx *ctx)
-{
- char *name = get_attr_name_ctx(ctx);
- print_inode_ni(base_inode(ctx));
- print_attribute(ctx->attr->type, name);
- free_name(&name);
-}
-
-static void print_differ(ntfs_attr *na)
-{
- print_na(na);
- printf("content: DIFFER\n");
-}
-
-static int cmp_buffer(u8 *buf1, u8 *buf2, long long int size, ntfs_attr *na)
-{
- if (memcmp(buf1, buf2, size)) {
- print_differ(na);
- return -1;
- }
- return 0;
-}
-
-struct cmp_ia {
- INDEX_ALLOCATION *ia;
- INDEX_ALLOCATION *tmp_ia;
- u8 *bitmap;
- u8 *byte;
- s64 bm_size;
-};
-
-static int setup_cmp_ia(ntfs_attr *na, struct cmp_ia *cia)
-{
- cia->bitmap = ntfs_attr_readall(na->ni, AT_BITMAP, na->name,
- na->name_len, &cia->bm_size);
- if (!cia->bitmap) {
- perr_println("Failed to readall BITMAP");
- return -1;
- }
- cia->byte = cia->bitmap;
-
- cia->tmp_ia = cia->ia = ntfs_malloc(na->data_size);
- if (!cia->tmp_ia)
- goto free_bm;
-
- if (ntfs_attr_pread(na, 0, na->data_size, cia->ia) != na->data_size) {
- perr_println("Failed to pread INDEX_ALLOCATION");
- goto free_ia;
- }
-
- return 0;
-free_ia:
- free(cia->ia);
-free_bm:
- free(cia->bitmap);
- return -1;
-}
-
-static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2)
-{
- struct cmp_ia cia1, cia2;
- int bit, ret1, ret2;
- u32 ib_size;
-
- if (setup_cmp_ia(na1, &cia1))
- return;
- if (setup_cmp_ia(na2, &cia2))
- return;
- /*
- * FIXME: ia can be the same even if the bitmap sizes are different.
- */
- if (cia1.bm_size != cia1.bm_size)
- goto out;
-
- if (cmp_buffer(cia1.bitmap, cia2.bitmap, cia1.bm_size, na1))
- goto out;
-
- if (cmp_buffer((u8 *)cia1.ia, (u8 *)cia2.ia, 0x18, na1))
- goto out;
-
- ib_size = le32_to_cpu(cia1.ia->index.allocated_size) + 0x18;
-
- bit = 0;
- while ((u8 *)cia1.tmp_ia < (u8 *)cia1.ia + na1->data_size) {
- if (*cia1.byte & (1 << bit)) {
- ret1 = ntfs_mst_post_read_fixup((NTFS_RECORD *)
- cia1.tmp_ia, ib_size);
- ret2 = ntfs_mst_post_read_fixup((NTFS_RECORD *)
- cia2.tmp_ia, ib_size);
- if (ret1 != ret2) {
- print_differ(na1);
- goto out;
- }
-
- if (ret1 == -1)
- continue;
-
- if (cmp_buffer(((u8 *)cia1.tmp_ia) + 0x18,
- ((u8 *)cia2.tmp_ia) + 0x18,
- le32_to_cpu(cia1.ia->
- index.index_length), na1))
- goto out;
- }
-
- cia1.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia1.tmp_ia + ib_size);
- cia2.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia2.tmp_ia + ib_size);
-
- bit++;
- if (bit > 7) {
- bit = 0;
- cia1.byte++;
- }
- }
-out:
- free(cia1.ia);
- free(cia2.ia);
- free(cia1.bitmap);
- free(cia2.bitmap);
- return;
-}
-
-static void cmp_attribute_data(ntfs_attr *na1, ntfs_attr *na2)
-{
- s64 pos;
- s64 count1 = 0, count2;
- u8 buf1[NTFS_BUF_SIZE];
- u8 buf2[NTFS_BUF_SIZE];
-
- for (pos = 0; pos <= na1->data_size; pos += count1) {
-
- count1 = ntfs_attr_pread(na1, pos, NTFS_BUF_SIZE, buf1);
- count2 = ntfs_attr_pread(na2, pos, NTFS_BUF_SIZE, buf2);
-
- if (count1 != count2) {
- print_na(na1);
- printf("abrupt length: %lld != %lld ",
- na1->data_size, na2->data_size);
- printf("(count: %lld != %lld)", count1, count2);
- puts("");
- return;
- }
-
- if (count1 == -1) {
- err_printf("%s read error: ", "cmp_attribute_data");
- print_na(na1);
- printf("len = %lld, pos = %lld\n", na1->data_size, pos);
- exit(1);
- }
-
- if (count1 == 0) {
-
- if (pos + count1 == na1->data_size)
- return; /* we are ready */
-
- err_printf("%s read error before EOF: ", "cmp_attribute_data");
- print_na(na1);
- printf("%lld != %lld\n", pos + count1, na1->data_size);
- exit(1);
- }
-
- if (cmp_buffer(buf1, buf2, count1, na1))
- return;
- }
-
- err_printf("%s read overrun: ", "cmp_attribute_data");
- print_na(na1);
- err_printf("(len = %lld, pos = %lld, count = %lld)\n",
- na1->data_size, pos, count1);
- exit(1);
-}
-
-static int cmp_attribute_header(ATTR_RECORD *a1, ATTR_RECORD *a2)
-{
- u32 header_size = offsetof(ATTR_RECORD, u.res.resident_end);
-
- if (a1->non_resident != a2->non_resident)
- return 1;
-
- if (a1->non_resident) {
- /*
- * FIXME: includes paddings which are not handled by ntfsinfo!
- */
- header_size = le32_to_cpu(a1->length);
- }
-
- return memcmp(a1, a2, header_size);
-}
-
-static void cmp_attribute(ntfs_attr_search_ctx *ctx1,
- ntfs_attr_search_ctx *ctx2)
-{
- ATTR_RECORD *a1 = ctx1->attr;
- ATTR_RECORD *a2 = ctx2->attr;
- ntfs_attr *na1, *na2;
-
- if (cmp_attribute_header(a1, a2)) {
- print_ctx(ctx1);
- printf("header: DIFFER\n");
- }
-
- na1 = ntfs_attr_open(base_inode(ctx1), a1->type, GET_ATTR_NAME(a1));
- na2 = ntfs_attr_open(base_inode(ctx2), a2->type, GET_ATTR_NAME(a2));
-
- if ((!na1 && na2) || (na1 && !na2)) {
- print_ctx(ctx1);
- printf("open: %s != %s\n", pret2str(na1), pret2str(na2));
- goto close_attribs;
- }
-
- if (na1 == NULL)
- goto close_attribs;
-
- if (na1->data_size != na2->data_size) {
- print_na(na1);
- printf("length: %lld != %lld\n", na1->data_size, na2->data_size);
- goto close_attribs;
- }
-
- if (ntfs_inode_badclus_bad(inumber(ctx1->ntfs_ino), ctx1->attr) == 1) {
- /*
- * If difference exists then it's already reported at the
- * attribute header since the mapping pairs must differ.
- */
- return;
- }
-
- if (na1->type == AT_INDEX_ALLOCATION)
- cmp_index_allocation(na1, na2);
- else
- cmp_attribute_data(na1, na2);
-
-close_attribs:
- ntfs_attr_close(na1);
- ntfs_attr_close(na2);
-}
-
-static void vprint_attribute(ATTR_TYPES atype, char *name)
-{
- if (!opt.verbose)
- return;
-
- printf("0x%x", atype);
- if (name)
- printf(":%s", name);
- printf(" ");
-}
-
-static void print_attributes(ntfs_inode *ni,
- ATTR_TYPES atype1,
- ATTR_TYPES atype2,
- char *name1,
- char *name2)
-{
- if (!opt.verbose)
- return;
-
- printf("Walking inode %llu attributes: ", inumber(ni));
- vprint_attribute(atype1, name1);
- vprint_attribute(atype2, name2);
- printf("\n");
-}
-
-static int new_name(ntfs_attr_search_ctx *ctx, char *prev_name)
-{
- int ret = 0;
- char *name = get_attr_name_ctx(ctx);
-
- if (prev_name && name) {
- if (strcmp(prev_name, name) != 0)
- ret = 1;
- } else if (prev_name || name)
- ret = 1;
-
- free_name(&name);
- return ret;
-
-}
-
-static int new_attribute(ntfs_attr_search_ctx *ctx,
- ATTR_TYPES prev_atype,
- char *prev_name)
-{
- if (!prev_atype && !prev_name)
- return 1;
-
- if (!ctx->attr->non_resident)
- return 1;
-
- if (prev_atype != ctx->attr->type)
- return 1;
-
- if (new_name(ctx, prev_name))
- return 1;
-
- if (opt.verbose) {
- print_inode(base_inode(ctx)->mft_no);
- print_attribute_ctx(ctx);
- printf("record %llu lowest_vcn %lld: SKIPPED\n",
- ctx->ntfs_ino->mft_no, ctx->attr->u.nonres.lowest_vcn);
- }
-
- return 0;
-}
-
-static void set_prev(char **prev_name, ATTR_TYPES *prev_atype,
- char *name, ATTR_TYPES atype)
-{
- free_name(prev_name);
- if (name) {
- *prev_name = strdup(name);
- if (!*prev_name)
- perr_exit("strdup error");
- }
-
- *prev_atype = atype;
-}
-
-static void set_cmp_attr(ntfs_attr_search_ctx *ctx, ATTR_TYPES *atype, char **name)
-{
- *atype = ctx->attr->type;
-
- free_name(name);
- *name = get_attr_name_ctx(ctx);
-}
-
-static int next_attr(ntfs_attr_search_ctx *ctx, ATTR_TYPES *atype, char **name,
- int *err)
-{
- int ret;
-
- ret = ntfs_attrs_walk(ctx);
- *err = errno;
- if (ret) {
- *atype = AT_END;
- free_name(name);
- } else
- set_cmp_attr(ctx, atype, name);
-
- return ret;
-}
-
-static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2)
-{
- int ret = -1;
- int old_ret1, ret1 = 0, ret2 = 0;
- int errno1 = 0, errno2 = 0;
- char *prev_name = NULL, *name1 = NULL, *name2 = NULL;
- ATTR_TYPES old_atype1, prev_atype = 0, atype1, atype2;
- ntfs_attr_search_ctx *ctx1, *ctx2;
-
- if (!(ctx1 = attr_get_search_ctx(ni1)))
- return -1;
- if (!(ctx2 = attr_get_search_ctx(ni2)))
- goto out;
-
- set_cmp_attr(ctx1, &atype1, &name1);
- set_cmp_attr(ctx2, &atype2, &name2);
-
- while (1) {
-
- old_atype1 = atype1;
- old_ret1 = ret1;
- if (!ret1 && (le32_to_cpu(atype1) <= le32_to_cpu(atype2) ||
- ret2))
- ret1 = next_attr(ctx1, &atype1, &name1, &errno1);
- if (!ret2 && (le32_to_cpu(old_atype1) >= le32_to_cpu(atype2) ||
- old_ret1))
- ret2 = next_attr(ctx2, &atype2, &name2, &errno2);
-
- print_attributes(ni1, atype1, atype2, name1, name2);
-
- if (ret1 && ret2) {
- if (errno1 != errno2) {
- print_inode_ni(ni1);
- printf("attribute walk (errno): %d != %d\n",
- errno1, errno2);
- }
- break;
- }
-
- if (ret2 || le32_to_cpu(atype1) < le32_to_cpu(atype2)) {
- if (new_attribute(ctx1, prev_atype, prev_name)) {
- print_ctx(ctx1);
- printf("presence: EXISTS != MISSING\n");
- set_prev(&prev_name, &prev_atype, name1,
- atype1);
- }
-
- } else if (ret1 || le32_to_cpu(atype1) > le32_to_cpu(atype2)) {
- if (new_attribute(ctx2, prev_atype, prev_name)) {
- print_ctx(ctx2);
- printf("presence: MISSING != EXISTS \n");
- set_prev(&prev_name, &prev_atype, name2, atype2);
- }
-
- } else /* atype1 == atype2 */ {
- if (new_attribute(ctx1, prev_atype, prev_name)) {
- cmp_attribute(ctx1, ctx2);
- set_prev(&prev_name, &prev_atype, name1, atype1);
- }
- }
- }
-
- free_name(&prev_name);
- ret = 0;
- ntfs_attr_put_search_ctx(ctx2);
-out:
- ntfs_attr_put_search_ctx(ctx1);
- return ret;
-}
-
-static int cmp_inodes(ntfs_volume *vol1, ntfs_volume *vol2)
-{
- u64 inode;
- int ret1, ret2;
- ntfs_inode *ni1, *ni2;
- struct progress_bar progress;
- int pb_flags = 0; /* progress bar flags */
- u64 nr_mft_records, nr_mft_records2;
-
- if (opt.show_progress)
- pb_flags |= NTFS_PROGBAR;
-
- nr_mft_records = get_nr_mft_records(vol1);
- nr_mft_records2 = get_nr_mft_records(vol2);
-
- if (nr_mft_records != nr_mft_records2) {
-
- printf("Number of mft records: %lld != %lld\n",
- nr_mft_records, nr_mft_records2);
-
- if (nr_mft_records > nr_mft_records2)
- nr_mft_records = nr_mft_records2;
- }
-
- progress_init(&progress, 0, nr_mft_records - 1, pb_flags);
- progress_update(&progress, 0);
-
- for (inode = 0; inode < nr_mft_records; inode++) {
-
- ret1 = inode_open(vol1, (MFT_REF)inode, &ni1);
- ret2 = inode_open(vol2, (MFT_REF)inode, &ni2);
-
- if (ret1 != ret2) {
- print_inode(inode);
- printf("open: %s != %s\n",
- err2string(ret1), err2string(ret2));
- goto close_inodes;
- }
-
- if (ret1 != NTFSCMP_OK)
- goto close_inodes;
-
- if (cmp_attributes(ni1, ni2) != 0) {
- inode_close(ni1);
- inode_close(ni2);
- return -1;
- }
-close_inodes:
- if (inode_close(ni1) != 0)
- return -1;
- if (inode_close(ni2) != 0)
- return -1;
-
- progress_update(&progress, inode);
- }
- return 0;
-}
-
-static ntfs_volume *mount_volume(const char *volume)
-{
- unsigned long mntflag;
- ntfs_volume *vol = NULL;
-
- if (ntfs_check_if_mounted(volume, &mntflag)) {
- perr_println("Failed to check '%s' mount state", volume);
- printf("Probably /etc/mtab is missing. It's too risky to "
- "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);
- }
-
- vol = ntfs_mount(volume, NTFS_MNT_RDONLY);
- if (vol == NULL) {
-
- int err = errno;
-
- perr_println("Opening '%s' as NTFS failed", volume);
- if (err == EINVAL)
- printf(invalid_ntfs_msg, volume);
- else if (err == EIO)
- puts(corrupt_volume_msg);
- else if (err == EPERM)
- puts(hibernated_volume_msg);
- exit(1);
- }
-
- return vol;
-}
-
-int main(int argc, char **argv)
-{
- ntfs_volume *vol1;
- ntfs_volume *vol2;
-
- printf("%s v%s (libntfs %s)\n", EXEC_NAME, VERSION,
- ntfs_libntfs_version());
-
- parse_options(argc, argv);
-
- utils_set_locale();
-
- vol1 = mount_volume(opt.vol1);
- vol2 = mount_volume(opt.vol2);
-
- if (cmp_inodes(vol1, vol2) != 0)
- exit(1);
-
- ntfs_umount(vol1, FALSE);
- ntfs_umount(vol2, FALSE);
-
- exit(0);
-}
-