summaryrefslogtreecommitdiff
Diffstat
-rwxr-xr-xAndroid.mk138
-rwxr-xr-xAndroid.mk.bak89
-rwxr-xr-xCREDITS20
-rwxr-xr-xINSTALL200
-rwxr-xr-xMakefile715
-rwxr-xr-xMakefile.am106
-rwxr-xr-xMakefile.in955
-rwxr-xr-xNEWS4
-rwxr-xr-xREADME80
-rwxr-xr-xTODO.ntfsprogs126
-rwxr-xr-xaclocal.m47091
-rwxr-xr-xcompile21
-rwxr-xr-xconfig.guess292
-rw-r--r--[-rwxr-xr-x]config.h165
-rwxr-xr-xconfig.h.in110
-rwxr-xr-xconfig.log3290
-rwxr-xr-xconfig.status1220
-rwxr-xr-xconfig.sub104
-rwxr-xr-xconfigure26448
-rwxr-xr-xconfigure.ac291
-rwxr-xr-xdepcomp87
-rwxr-xr-xinclude/Makefile.in181
-rwxr-xr-xinclude/fuse-lite/Makefile.in112
-rwxr-xr-xinclude/fuse-lite/fuse.h61
-rwxr-xr-xinclude/fuse-lite/fuse_common.h49
-rwxr-xr-xinclude/fuse-lite/fuse_kernel.h6
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel.h20
-rwxr-xr-xinclude/ntfs-3g/Makefile.am4
-rwxr-xr-xinclude/ntfs-3g/Makefile.in163
-rwxr-xr-xinclude/ntfs-3g/acls.h3
-rwxr-xr-xinclude/ntfs-3g/attrib.h50
-rwxr-xr-xinclude/ntfs-3g/cache.h7
-rwxr-xr-xinclude/ntfs-3g/compat.h6
-rwxr-xr-xinclude/ntfs-3g/compress.h6
-rwxr-xr-xinclude/ntfs-3g/debug.h4
-rwxr-xr-xinclude/ntfs-3g/device.h18
-rwxr-xr-xinclude/ntfs-3g/device_io.h21
-rwxr-xr-xinclude/ntfs-3g/dir.h11
-rwxr-xr-xinclude/ntfs-3g/layout.h32
-rwxr-xr-xinclude/ntfs-3g/lcnalloc.h1
-rwxr-xr-xinclude/ntfs-3g/logging.h3
-rwxr-xr-xinclude/ntfs-3g/mst.h3
-rwxr-xr-xinclude/ntfs-3g/ntfstime.h12
-rwxr-xr-xinclude/ntfs-3g/param.h72
-rwxr-xr-xinclude/ntfs-3g/realpath.h24
-rwxr-xr-xinclude/ntfs-3g/runlist.h3
-rwxr-xr-xinclude/ntfs-3g/security.h20
-rwxr-xr-xinclude/ntfs-3g/types.h8
-rwxr-xr-xinclude/ntfs-3g/unistr.h13
-rwxr-xr-xinclude/ntfs-3g/volume.h78
-rwxr-xr-xinclude/ntfs-3g/xattrs.h75
-rwxr-xr-xinstall-sh5
-rwxr-xr-xlibfuse-lite/Makefile.am3
-rwxr-xr-xlibfuse-lite/Makefile.in188
-rwxr-xr-xlibfuse-lite/fuse.c418
-rwxr-xr-xlibfuse-lite/fuse_kern_chan.c2
-rwxr-xr-xlibfuse-lite/fuse_lowlevel.c53
-rwxr-xr-xlibfuse-lite/fuse_opt.c20
-rwxr-xr-xlibfuse-lite/fuse_session.c12
-rwxr-xr-xlibfuse-lite/fusermount.c97
-rwxr-xr-xlibfuse-lite/helper.c21
-rwxr-xr-xlibfuse-lite/mount.c486
-rwxr-xr-xlibfuse-lite/mount_util.c246
-rwxr-xr-xlibfuse-lite/mount_util.h11
-rwxr-xr-xlibntfs-3g/Makefile.am15
-rwxr-xr-xlibntfs-3g/Makefile.in420
-rwxr-xr-xlibntfs-3g/acls.c219
-rwxr-xr-xlibntfs-3g/attrib.c1205
-rwxr-xr-xlibntfs-3g/bootsect.c4
-rwxr-xr-xlibntfs-3g/cache.c7
-rwxr-xr-xlibntfs-3g/compress.c962
-rwxr-xr-xlibntfs-3g/device.c252
-rwxr-xr-xlibntfs-3g/dir.c374
-rwxr-xr-xlibntfs-3g/efs.c217
-rwxr-xr-xlibntfs-3g/index.c30
-rwxr-xr-xlibntfs-3g/inode.c46
-rwxr-xr-xlibntfs-3g/lcnalloc.c36
-rw-r--r--libntfs-3g/libntfs-3g.pc10
-rw-r--r--libntfs-3g/libntfs-3g.script.so2
-rwxr-xr-xlibntfs-3g/logfile.c23
-rwxr-xr-xlibntfs-3g/logging.c24
-rwxr-xr-xlibntfs-3g/mft.c12
-rwxr-xr-xlibntfs-3g/mst.c24
-rwxr-xr-xlibntfs-3g/object_id.c9
-rwxr-xr-xlibntfs-3g/realpath.c103
-rwxr-xr-xlibntfs-3g/reparse.c67
-rwxr-xr-xlibntfs-3g/runlist.c62
-rwxr-xr-xlibntfs-3g/security.c345
-rwxr-xr-xlibntfs-3g/unistr.c244
-rwxr-xr-xlibntfs-3g/unix_io.c19
-rwxr-xr-xlibntfs-3g/volume.c365
-rwxr-xr-xlibntfs-3g/win32_io.c708
-rwxr-xr-xlibntfs-3g/xattrs.c791
-rwxr-xr-xlibtool9301
-rwxr-xr-xltmain.sh8439
-rwxr-xr-xm4/libtool.m47377
-rwxr-xr-xm4/ltoptions.m4368
-rwxr-xr-xm4/ltsugar.m4123
-rwxr-xr-xm4/ltversion.m423
-rwxr-xr-xm4/lt~obsolete.m492
-rwxr-xr-xmissing49
-rwxr-xr-xntfsprogs/Makefile.am154
-rwxr-xr-xntfsprogs/Makefile.in1199
-rwxr-xr-xntfsprogs/attrdef.c168
-rwxr-xr-xntfsprogs/attrdef.h7
-rwxr-xr-xntfsprogs/boot.c268
-rwxr-xr-xntfsprogs/boot.h7
-rwxr-xr-xntfsprogs/cluster.c118
-rwxr-xr-xntfsprogs/cluster.h39
-rwxr-xr-xntfsprogs/list.h194
-rw-r--r--ntfsprogs/mkntfs.8290
-rwxr-xr-xntfsprogs/mkntfs.8.in290
-rwxr-xr-xntfsprogs/mkntfs.c5177
-rw-r--r--ntfsprogs/ntfscat.8136
-rwxr-xr-xntfsprogs/ntfscat.8.in136
-rwxr-xr-xntfsprogs/ntfscat.c440
-rwxr-xr-xntfsprogs/ntfscat.h46
-rwxr-xr-xntfsprogs/ntfsck.c883
-rw-r--r--ntfsprogs/ntfsclone.8391
-rwxr-xr-xntfsprogs/ntfsclone.8.in391
-rwxr-xr-xntfsprogs/ntfsclone.c2701
-rw-r--r--ntfsprogs/ntfscluster.8124
-rwxr-xr-xntfsprogs/ntfscluster.8.in124
-rwxr-xr-xntfsprogs/ntfscluster.c563
-rwxr-xr-xntfsprogs/ntfscluster.h63
-rw-r--r--ntfsprogs/ntfscmp.877
-rwxr-xr-xntfsprogs/ntfscmp.8.in77
-rwxr-xr-xntfsprogs/ntfscmp.c1012
-rw-r--r--ntfsprogs/ntfscp.8111
-rwxr-xr-xntfsprogs/ntfscp.8.in111
-rwxr-xr-xntfsprogs/ntfscp.c590
-rwxr-xr-xntfsprogs/ntfsdecrypt.c1436
-rwxr-xr-xntfsprogs/ntfsdump_logfile.c779
-rw-r--r--ntfsprogs/ntfsfix.881
-rwxr-xr-xntfsprogs/ntfsfix.8.in81
-rwxr-xr-xntfsprogs/ntfsfix.c1657
-rw-r--r--ntfsprogs/ntfsinfo.889
-rwxr-xr-xntfsprogs/ntfsinfo.8.in89
-rwxr-xr-xntfsprogs/ntfsinfo.c2384
-rw-r--r--ntfsprogs/ntfslabel.8118
-rwxr-xr-xntfsprogs/ntfslabel.8.in118
-rwxr-xr-xntfsprogs/ntfslabel.c458
-rw-r--r--ntfsprogs/ntfsls.8172
-rwxr-xr-xntfsprogs/ntfsls.8.in172
-rwxr-xr-xntfsprogs/ntfsls.c717
-rwxr-xr-xntfsprogs/ntfsmftalloc.c368
-rwxr-xr-xntfsprogs/ntfsmove.c923
-rwxr-xr-xntfsprogs/ntfsmove.h46
-rw-r--r--ntfsprogs/ntfsprogs.869
-rwxr-xr-xntfsprogs/ntfsprogs.8.in69
-rw-r--r--ntfsprogs/ntfsresize.8326
-rwxr-xr-xntfsprogs/ntfsresize.8.in326
-rwxr-xr-xntfsprogs/ntfsresize.c4497
-rwxr-xr-xntfsprogs/ntfstruncate.c809
-rw-r--r--ntfsprogs/ntfsundelete.8324
-rwxr-xr-xntfsprogs/ntfsundelete.8.in324
-rwxr-xr-xntfsprogs/ntfsundelete.c2490
-rwxr-xr-xntfsprogs/ntfsundelete.h112
-rwxr-xr-xntfsprogs/ntfswipe.c2131
-rwxr-xr-xntfsprogs/ntfswipe.h54
-rwxr-xr-xntfsprogs/sd.c607
-rwxr-xr-xntfsprogs/sd.h11
-rwxr-xr-xntfsprogs/utils.c1184
-rwxr-xr-xntfsprogs/utils.h137
-rwxr-xr-xprog.IAB1071
-rwxr-xr-xprog.IAD5
-rwxr-xr-xprog.IMB466
-rwxr-xr-xprog.IMD2
-rwxr-xr-xprog.PFI2
-rwxr-xr-xprog.PO1
-rwxr-xr-xprog.PR14
-rwxr-xr-xprog.PRI219
-rwxr-xr-xprog.PS979
-rwxr-xr-xprog.SearchResults3
-rwxr-xr-xprog.WK39
-rwxr-xr-xsrc/Makefile.am86
-rwxr-xr-xsrc/Makefile.in938
-rwxr-xr-xsrc/lowntfs-3g.c1538
-rw-r--r--src/ntfs-3g.8448
-rwxr-xr-xsrc/ntfs-3g.8.in217
-rwxr-xr-xsrc/ntfs-3g.c1357
-rw-r--r--src/ntfs-3g.probe.881
-rwxr-xr-xsrc/ntfs-3g.probe.8.in4
-rwxr-xr-xsrc/ntfs-3g.probe.c9
-rw-r--r--src/ntfs-3g.secaudit.8184
-rwxr-xr-xsrc/ntfs-3g.secaudit.8.in15
-rw-r--r--src/ntfs-3g.usermap.896
-rwxr-xr-xsrc/ntfs-3g_common.c745
-rwxr-xr-xsrc/ntfs-3g_common.h185
-rwxr-xr-xsrc/secaudit.c673
-rwxr-xr-xsrc/secaudit.h32
-rwxr-xr-xsrc/usermap.c3
-rw-r--r--[-rwxr-xr-x]stamp-h10
193 files changed, 80411 insertions, 44563 deletions
diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c
new file mode 100755
index 0000000..469d1d9
--- a/dev/null
+++ b/ntfsprogs/ntfscmp.c
@@ -0,0 +1,1012 @@
+/**
+ * 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 "mst.h"
+#include "support.h"
+#include "utils.h"
+#include "misc.h"
+/* #include "version.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->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",
+ (unsigned long long)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", (long long)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 ", (unsigned long long)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 ",
+ (long long)na1->data_size,
+ (long long)na2->data_size);
+ printf("(count: %lld != %lld)",
+ (long long)count1, (long long)count2);
+ puts("");
+ return;
+ }
+
+ if (count1 == -1) {
+ err_printf("%s read error: ", __FUNCTION__);
+ print_na(na1);
+ printf("len = %lld, pos = %lld\n",
+ (long long)na1->data_size, (long long)pos);
+ exit(1);
+ }
+
+ if (count1 == 0) {
+
+ if (pos + count1 == na1->data_size)
+ return; /* we are ready */
+
+ err_printf("%s read error before EOF: ", __FUNCTION__);
+ print_na(na1);
+ printf("%lld != %lld\n", (long long)pos + count1,
+ (long long)na1->data_size);
+ exit(1);
+ }
+
+ if (cmp_buffer(buf1, buf2, count1, na1))
+ return;
+ }
+
+ err_printf("%s read overrun: ", __FUNCTION__);
+ print_na(na1);
+ err_printf("(len = %lld, pos = %lld, count = %lld)\n",
+ (long long)na1->data_size, (long long)pos, (long long)count1);
+ exit(1);
+}
+
+static int cmp_attribute_header(ATTR_RECORD *a1, ATTR_RECORD *a2)
+{
+ u32 header_size = offsetof(ATTR_RECORD, 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",
+ (long long)na1->data_size, (long long)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.
+ */
+ goto close_attribs;
+ }
+
+ 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: ",
+ (unsigned long long)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",
+ (unsigned long long)ctx->ntfs_ino->mft_no,
+ (long long)ctx->attr->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",
+ (long long)nr_mft_records, (long long)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-3g)\n", EXEC_NAME, 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);
+
+ return (0);
+}
+