Merge branch 'edge' into edge.strict_endians

Conflicts:
	libntfs-3g/dir.c
	libntfs-3g/index.c
	libntfs-3g/runlist.c
	ntfsprogs/ntfsfix.c
	ntfsprogs/ntfsinfo.c
edge.strict_endians
Erik Larsson 2016-02-05 18:02:02 +01:00
commit 34bb449324
43 changed files with 10413 additions and 473 deletions

View File

@ -657,6 +657,7 @@ AC_CONFIG_FILES([
ntfsprogs/ntfswipe.8
ntfsprogs/ntfstruncate.8
ntfsprogs/ntfsfallocate.8
ntfsprogs/ntfsrecover.8
src/Makefile
src/ntfs-3g.8
src/ntfs-3g.probe.8

View File

@ -2557,6 +2557,7 @@ typedef enum {
IO_REPARSE_TAG_SIS = const_cpu_to_le32(0x80000007),
IO_REPARSE_TAG_SYMLINK = const_cpu_to_le32(0xA000000C),
IO_REPARSE_TAG_WIM = const_cpu_to_le32(0x80000008),
IO_REPARSE_TAG_WOF = const_cpu_to_le32(0x80000017),
IO_REPARSE_TAG_VALID_VALUES = const_cpu_to_le32(0xf000ffff),
#if !ENABLE_STRICT_ENDIANNESS_CHECKING

View File

@ -76,6 +76,14 @@ enum {
/* only update the final extent of a runlist when appending data */
#define PARTIAL_RUNLIST_UPDATING 1
/*
* Parameters for upper-case table
*/
/* Create upper-case tables as defined by Windows 6.1 (Win7) */
#define UPCASE_MAJOR 6
#define UPCASE_MINOR 1
/*
* Parameters for user and xattr mappings
*/
@ -102,12 +110,14 @@ enum {
* Possible values for high level :
* 1 : no cache, kernel control (recommended)
* 4 : no cache, file system control
* 6 : kernel/fuse cache, file system control (OpenIndiana only)
* 7 : no cache, kernel control for ACLs
*
* Possible values for low level :
* 2 : no cache, kernel control
* 3 : use kernel/fuse cache, kernel control (external fuse >= 2.8)
* 5 : no cache, file system control (recommended)
* 5 : no cache, file system control (recommended on Linux)
* 6 : kernel/fuse cache, file system control (OpenIndiana only)
* 8 : no cache, kernel control for ACLs
*
* Use of options 7 and 8 requires a patch to fuse
@ -116,14 +126,19 @@ enum {
*/
#if defined(__sun) && defined(__SVR4)
#define HPERMSCONFIG 4 /* access control by kernel is broken on OpenIndiana */
/*
* Access control by kernel is not implemented on OpenIndiana,
* however care is taken of cacheing hard-linked files.
*/
#define HPERMSCONFIG 6
#define LPERMSCONFIG 6
#else
#define HPERMSCONFIG 1
#endif
#if defined(FUSE_INTERNAL) || !defined(FUSE_VERSION) || (FUSE_VERSION < 28)
#define LPERMSCONFIG 5
#else
#define LPERMSCONFIG 3
#endif
#endif /* defined(__sun) && defined(__SVR4) */
#endif /* defined _NTFS_PARAM_H */

View File

@ -211,22 +211,6 @@ enum {
extern BOOL ntfs_guid_is_zero(const GUID *guid);
extern char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str);
/**
* ntfs_sid_is_valid - determine if a SID is valid
* @sid: SID for which to determine if it is valid
*
* Determine if the SID pointed to by @sid is valid.
*
* Return TRUE if it is valid and FALSE otherwise.
*/
static __inline__ BOOL ntfs_sid_is_valid(const SID *sid)
{
if (!sid || sid->revision != SID_REVISION ||
sid->sub_authority_count > SID_MAX_SUB_AUTHORITIES)
return FALSE;
return TRUE;
}
extern int ntfs_sid_to_mbs_size(const SID *sid);
extern char *ntfs_sid_to_mbs(const SID *sid, char *sid_str,
size_t sid_str_size);

View File

@ -69,7 +69,13 @@ static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
attr->nlink = stbuf->st_nlink;
attr->uid = stbuf->st_uid;
attr->gid = stbuf->st_gid;
#if defined(__SOLARIS__) && defined(_LP64)
/* Must pack the device the old way (attr->rdev limited to 32 bits) */
attr->rdev = ((major(stbuf->st_rdev) & 0x3fff) << 18)
| (minor(stbuf->st_rdev) & 0x3ffff);
#else
attr->rdev = stbuf->st_rdev;
#endif
attr->size = stbuf->st_size;
attr->blocks = stbuf->st_blocks;
attr->atime = stbuf->st_atime;
@ -553,9 +559,16 @@ static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
else
name = (const char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
if (req->f->op.mknod)
if (req->f->op.mknod) {
#if defined(__SOLARIS__) && defined(_LP64)
/* Must unpack the device, as arg->rdev is limited to 32 bits */
req->f->op.mknod(req, nodeid, name, arg->mode,
makedev((arg->rdev >> 18) & 0x3ffff,
arg->rdev & 0x3fff));
#else
req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
else
#endif
} else
fuse_reply_err(req, ENOSYS);
}

View File

@ -22,13 +22,13 @@ static void exit_handler(int sig)
fuse_session_exit(fuse_instance);
}
static int set_one_signal_handler(int sig, void (*handler)(int))
static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
{
struct sigaction sa;
struct sigaction old_sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handler;
sa.sa_handler = remove ? SIG_DFL : handler;
sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
@ -37,7 +37,7 @@ static int set_one_signal_handler(int sig, void (*handler)(int))
return -1;
}
if (old_sa.sa_handler == SIG_DFL &&
if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
sigaction(sig, &sa, NULL) == -1) {
perror("fuse: cannot set signal handler");
return -1;
@ -47,10 +47,10 @@ static int set_one_signal_handler(int sig, void (*handler)(int))
int fuse_set_signal_handlers(struct fuse_session *se)
{
if (set_one_signal_handler(SIGHUP, exit_handler) == -1 ||
set_one_signal_handler(SIGINT, exit_handler) == -1 ||
set_one_signal_handler(SIGTERM, exit_handler) == -1 ||
set_one_signal_handler(SIGPIPE, SIG_IGN) == -1)
if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1)
return -1;
fuse_instance = se;
@ -65,9 +65,9 @@ void fuse_remove_signal_handlers(struct fuse_session *se)
else
fuse_instance = NULL;
set_one_signal_handler(SIGHUP, SIG_DFL);
set_one_signal_handler(SIGINT, SIG_DFL);
set_one_signal_handler(SIGTERM, SIG_DFL);
set_one_signal_handler(SIGPIPE, SIG_DFL);
set_one_signal_handler(SIGHUP, exit_handler, 1);
set_one_signal_handler(SIGINT, exit_handler, 1);
set_one_signal_handler(SIGTERM, exit_handler, 1);
set_one_signal_handler(SIGPIPE, SIG_IGN, 1);
}

View File

@ -66,6 +66,7 @@ int fuse_mnt_add_mount(const char *progname, const char *fsname,
return -1;
}
if (res == 0) {
char *env = NULL;
char templ[] = "/tmp/fusermountXXXXXX";
char *tmp;
@ -87,8 +88,8 @@ int fuse_mnt_add_mount(const char *progname, const char *fsname,
exit(1);
}
rmdir(tmp);
execl("/sbin/mount", "/sbin/mount", "-F", type, "-o", opts,
fsname, mnt, NULL);
execle("/sbin/mount", "/sbin/mount", "-F", type, "-o", opts,
fsname, mnt, NULL, &env);
fprintf(stderr, "%s: failed to execute /sbin/mount: %s\n", progname,
strerror(errno));
exit(1);
@ -120,9 +121,16 @@ int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
return -1;
}
if (res == 0) {
char *env = NULL;
setuid(geteuid());
execl("/sbin/umount", "/sbin/umount", !lazy ? "-f" : NULL, mnt,
NULL);
if (lazy) {
execle("/sbin/umount", "/sbin/umount", mnt,
NULL, &env);
} else {
execle("/sbin/umount", "/sbin/umount", "-f", mnt,
NULL, &env);
}
fprintf(stderr, "%s: failed to execute /sbin/umount: %s\n", progname,
strerror(errno));
exit(1);
@ -302,6 +310,7 @@ int fuse_mnt_add_mount(const char *progname, const char *fsname,
return 0;
}
if (res == 0) {
char *env = NULL;
char templ[] = "/tmp/fusermountXXXXXX";
char *tmp;
@ -325,8 +334,8 @@ int fuse_mnt_add_mount(const char *progname, const char *fsname,
exit(1);
}
rmdir(tmp);
execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
fsname, mnt, NULL);
execle("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
fsname, mnt, NULL, &env);
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname,
strerror(errno));
exit(1);
@ -353,11 +362,18 @@ int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
return -1;
}
if (res == 0) {
char *env = NULL;
if (setuid(geteuid()))
fprintf(stderr, "%s: failed to setuid : %s\n", progname,
strerror(errno));
execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL,
NULL);
if (lazy) {
execle("/bin/umount", "/bin/umount", "-i", mnt, "-l",
NULL, &env);
} else {
execle("/bin/umount", "/bin/umount", "-i", mnt,
NULL, &env);
}
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname,
strerror(errno));
exit(1);

View File

@ -4,7 +4,7 @@
* This module is part of ntfs-3g library, but may also be
* integrated in tools running over Linux or Windows
*
* Copyright (c) 2007-2014 Jean-Pierre Andre
* Copyright (c) 2007-2015 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -362,16 +362,18 @@ unsigned int ntfs_attr_size(const char *attr)
return (attrsz);
}
/*
* Do sanity checks on a SID read from storage
* (just check revision and number of authorities)
/**
* ntfs_valid_sid - determine if a SID is valid
* @sid: SID for which to determine if it is valid
*
* Determine if the SID pointed to by @sid is valid.
*
* Return TRUE if it is valid and FALSE otherwise.
*/
BOOL ntfs_valid_sid(const SID *sid)
{
return ((sid->revision == SID_REVISION)
&& (sid->sub_authority_count >= 1)
&& (sid->sub_authority_count <= 8));
return sid && sid->revision == SID_REVISION &&
sid->sub_authority_count <= SID_MAX_SUB_AUTHORITIES;
}
/*
@ -2314,10 +2316,21 @@ return (0);
mapping,flags,pxace,pset);
break;
case POSIX_ACL_GROUP :
case POSIX_ACL_GROUP_OBJ :
/* denials and grants for group when needed */
if (pset->groupowns && !pset->adminowns
&& (pset->grpperms == pset->othperms)
&& !pset->designates && !pset->withmask) {
ok = TRUE;
} else {
ok = build_group_denials_grant(pacl,gsid,
mapping,flags,pxace,pset);
}
break;
/* denials and grants for groups */
case POSIX_ACL_GROUP :
/* denials and grants for designated groups */
ok = build_group_denials_grant(pacl,gsid,
mapping,flags,pxace,pset);
@ -2574,7 +2587,6 @@ static int buildacls(char *secattr, int offs, mode_t mode, int isdir,
/* this ACE will be inserted after denials for group */
if (adminowns
|| groupowns
|| (((mode >> 3) ^ mode) & 7)) {
grants = WORLD_RIGHTS;
if (isdir) {

View File

@ -5,7 +5,7 @@
* Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004-2007 Yura Pakhuchiy
* Copyright (c) 2007-2014 Jean-Pierre Andre
* Copyright (c) 2007-2015 Jean-Pierre Andre
* Copyright (c) 2010 Erik Larsson
*
* This program/include file is free software; you can redistribute it and/or
@ -1780,7 +1780,8 @@ static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize,
* appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of
* invalid arguments.
*/
s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
static s64 ntfs_attr_pwrite_i(ntfs_attr *na, const s64 pos, s64 count,
const void *b)
{
s64 written, to_write, ofs, old_initialized_size, old_data_size;
s64 total = 0;
@ -1799,15 +1800,6 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
BOOL wasnonresident = FALSE;
BOOL compressed;
ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count "
"0x%llx.\n", (long long)na->ni->mft_no, le32_to_cpu(na->type),
(long long)pos, (long long)count);
if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
errno = EINVAL;
ntfs_log_perror("%s", __FUNCTION__);
goto errno_set;
}
vol = na->ni->vol;
compressed = !le16_eq(le16_and(na->data_flags, ATTR_COMPRESSION_MASK),
const_cpu_to_le16(0));
@ -2268,7 +2260,6 @@ done:
NAttrClearDataAppending(na);
}
out:
ntfs_log_leave("\n");
return total;
rl_err_out:
eo = errno;
@ -2335,6 +2326,39 @@ errno_set:
goto out;
}
s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
{
s64 total;
s64 written;
ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count "
"0x%llx.\n", (long long)na->ni->mft_no, le32_to_cpu(na->type),
(long long)pos, (long long)count);
total = 0;
if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
errno = EINVAL;
written = -1;
ntfs_log_perror("%s", __FUNCTION__);
goto out;
}
/*
* Compressed attributes may be written partially, so
* we may have to iterate.
*/
do {
written = ntfs_attr_pwrite_i(na, pos + total,
count - total, (const u8*)b + total);
if (written > 0)
total += written;
} while ((written > 0) && (total < count));
out :
ntfs_log_leave("\n");
return (total > 0 ? total : written);
}
int ntfs_attr_pclose(ntfs_attr *na)
{
s64 ofs;

View File

@ -1131,6 +1131,7 @@ static s32 ntfs_comp_set(ntfs_attr *na, runlist_element *rl,
outbuf[compsz++] = 0;
/* write a full cluster, to avoid partial reading */
rounded = ((compsz - 1) | (clsz - 1)) + 1;
memset(&outbuf[compsz], 0, rounded - compsz);
written = write_clusters(vol, rl, offs, rounded, outbuf);
if (written != rounded) {
/*

View File

@ -2157,11 +2157,6 @@ static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
goto err_out;
}
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)
&& !ntfs_possible_symlink(ni)) {
err = EOPNOTSUPP;
goto err_out;
}
if (NVolHideDotFiles(dir_ni->vol)) {
/* Set hidden flag according to the latest name */
if ((name_len > 1)

View File

@ -1175,8 +1175,7 @@ retry :
* index, we may have to move the root to an extent
*/
if ((errno == ENOSPC)
&& !ctx->al_entry
&& !ntfs_inode_add_attrlist(icx->ni)) {
&& (ctx->al_entry || !ntfs_inode_add_attrlist(icx->ni))) {
ntfs_attr_put_search_ctx(ctx);
ctx = (ntfs_attr_search_ctx*)NULL;
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len,
@ -1842,7 +1841,8 @@ err_out:
goto out;
}
int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
int ntfs_index_remove(ntfs_inode *dir_ni,
ntfs_inode *ni __attribute__((unused)),
const void *key, const int keylen)
{
int ret = STATUS_ERROR;
@ -1857,13 +1857,6 @@ int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
if (ntfs_index_lookup(key, keylen, icx))
goto err_out;
if (!le32_andz(((FILE_NAME_ATTR *)icx->data)->file_attributes,
FILE_ATTR_REPARSE_POINT)
&& !ntfs_possible_symlink(ni)) {
errno = EOPNOTSUPP;
goto err_out;
}
ret = ntfs_index_rm(icx);
if (ret == STATUS_ERROR)
goto err_out;

View File

@ -3,8 +3,8 @@
*
* This module is part of ntfs-3g library
*
* Copyright (c) 2014 Jean-Pierre Andre
* Copyright (c) 2014 Red Hat, Inc.
* Copyright (c) 2014-2015 Jean-Pierre Andre
* Copyright (c) 2014 Red Hat, Inc.
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -232,7 +232,7 @@ not_found:
* are found and TRIM requests are sent to the block device. 'minlen'
* is the minimum continguous free range to discard.
*/
static int fstrim(ntfs_volume *vol, void *data)
static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
{
struct fstrim_range *range = data;
u64 start = range->start;
@ -248,6 +248,8 @@ static int fstrim(ntfs_volume *vol, void *data)
(unsigned long long) len,
(unsigned long long) minlen);
*trimmed = 0;
/* Fail if user tries to use the fstrim -o/-l/-m options.
* XXX We could fix these limitations in future.
*/
@ -341,6 +343,8 @@ static int fstrim(ntfs_volume *vol, void *data)
if (ret)
goto free_out;
*trimmed += (end_lcn - start_lcn)
<< vol->cluster_size_bits;
start_lcn = end_lcn-1;
}
}
@ -364,11 +368,16 @@ int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg __attribute__((unused)),
case FITRIM:
if (!ni || !data)
ret = -EINVAL;
else
ret = fstrim(ni->vol, data);
else {
u64 trimmed;
struct fstrim_range *range = (struct fstrim_range*)data;
ret = fstrim(ni->vol, data, &trimmed);
range->len = trimmed;
}
break;
#else
#warning FITRIM or BLKDISCARD not defined
#warning Trimming not supported : FITRIM or BLKDISCARD not defined
#endif
default :
ret = -EINVAL;

View File

@ -5,7 +5,7 @@
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2004-2008 Szabolcs Szakacsits
* Copyright (c) 2005 Yura Pakhuchiy
* Copyright (c) 2014 Jean-Pierre Andre
* Copyright (c) 2014-2015 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -1620,7 +1620,6 @@ err_out:
* when reading the bitmap but if we are careful, we should be able to avoid
* all problems.
*/
//ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
{
s64 ll, bit;
@ -1628,6 +1627,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
MFT_RECORD *m;
ntfs_inode *ni = NULL;
int err;
u32 usa_ofs;
le16 seq_no, usn;
if (base_ni)
@ -1754,7 +1754,16 @@ found_free_rec:
goto retry;
}
seq_no = m->sequence_number;
usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs));
/*
* As ntfs_mft_record_read() returns what has been read
* even when the fixups have been found bad, we have to
* check where we fetch the initial usn from.
*/
usa_ofs = le16_to_cpu(m->usa_ofs);
if (!(usa_ofs & 1) && (usa_ofs < NTFS_BLOCK_SIZE)) {
usn = *(le16*)((u8*)m + usa_ofs);
} else
usn = const_cpu_to_le16(1);
if (ntfs_mft_record_layout(vol, bit, m)) {
ntfs_log_error("Failed to re-format mft record.\n");
free(m);

View File

@ -422,8 +422,10 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter)
/*
* Do some sanity checks on reparse data
*
* The only general check is about the size (at least the tag must
* be present)
* Microsoft reparse points have an 8-byte header whereas
* non-Microsoft reparse points have a 24-byte header. In each case,
* 'reparse_data_length' must equal the number of non-header bytes.
*
* If the reparse data looks like a junction point or symbolic
* link, more checks can be done.
*
@ -440,8 +442,11 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
ok = ni && reparse_attr
&& (size >= sizeof(REPARSE_POINT))
&& !le32_eq(reparse_attr->reparse_tag, IO_REPARSE_TAG_RESERVED_ZERO)
&& (((size_t)le16_to_cpu(reparse_attr->reparse_data_length)
+ sizeof(REPARSE_POINT)) == size);
+ sizeof(REPARSE_POINT)
+ (!le32_andz(reparse_attr->reparse_tag,
IO_REPARSE_TAG_IS_MICROSOFT) ? 0 : sizeof(GUID))) == size);
if (ok) {
/* switch (reparse_attr->reparse_tag) { */
if (le32_eq(reparse_attr->reparse_tag, IO_REPARSE_TAG_MOUNT_POINT)) {

View File

@ -939,40 +939,45 @@ mpa_err:
"attribute.\n");
goto err_out;
}
/* Setup not mapped runlist element if this is the base extent. */
if (sle64_cmpz(attr->lowest_vcn)) {
VCN max_cluster;
max_cluster = ((sle64_to_cpu(attr->allocated_size) +
/*
* If this is the base of runlist (if 'lowest_vcn' is 0), then
* 'allocated_size' is valid, and we can use it to compute the total
* number of clusters across all extents. If the runlist covers all
* clusters, then it fits into a single extent and we can terminate
* the runlist with LCN_NOENT. Otherwise, we must terminate the runlist
* with LCN_RL_NOT_MAPPED and let the caller look for more extents.
*/
if (sle64_cmpz(attr->lowest_vcn)) {
VCN num_clusters;
num_clusters = ((sle64_to_cpu(attr->allocated_size) +
vol->cluster_size - 1) >>
vol->cluster_size_bits) - 1;
/*
* A highest_vcn of zero means this is a single extent
* attribute so simply terminate the runlist with LCN_ENOENT).
*/
if (deltaxcn) {
vol->cluster_size_bits);
if (num_clusters > vcn) {
/*
* If there is a difference between the highest_vcn and
* the highest cluster, the runlist is either corrupt
* or, more likely, there are more extents following
* this one.
* The runlist doesn't cover all the clusters, so there
* must be more extents.
*/
if (deltaxcn < max_cluster) {
ntfs_log_debug("More extents to follow; deltaxcn = "
"0x%llx, max_cluster = 0x%llx\n",
(long long)deltaxcn,
(long long)max_cluster);
rl[rlpos].vcn = vcn;
vcn += rl[rlpos].length = max_cluster - deltaxcn;
rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
rlpos++;
} else if (deltaxcn > max_cluster) {
ntfs_log_debug("Corrupt attribute. deltaxcn = "
"0x%llx, max_cluster = 0x%llx\n",
(long long)deltaxcn,
(long long)max_cluster);
goto mpa_err;
}
ntfs_log_debug("More extents to follow; vcn = 0x%llx, "
"num_clusters = 0x%llx\n",
(long long)vcn,
(long long)num_clusters);
rl[rlpos].vcn = vcn;
vcn += rl[rlpos].length = num_clusters - vcn;
rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
rlpos++;
} else if (vcn > num_clusters) {
/*
* There are more VCNs in the runlist than expected, so
* the runlist is corrupt.
*/
ntfs_log_error("Corrupt attribute. vcn = 0x%llx, "
"num_clusters = 0x%llx\n",
(long long)vcn,
(long long)num_clusters);
goto mpa_err;
}
rl[rlpos].lcn = (LCN)LCN_ENOENT;
} else /* Not the base extent. There may be more extents to follow. */

View File

@ -4,7 +4,7 @@
* Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2006 Yura Pakhuchiy
* Copyright (c) 2007-2014 Jean-Pierre Andre
* Copyright (c) 2007-2015 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -224,7 +224,7 @@ int ntfs_sid_to_mbs_size(const SID *sid)
{
int size, i;
if (!ntfs_sid_is_valid(sid)) {
if (!ntfs_valid_sid(sid)) {
errno = EINVAL;
return -1;
}
@ -298,7 +298,7 @@ char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
* No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
* check @sid, too. 8 is the minimum SID string size.
*/
if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
if (sid_str && (sid_str_size < 8 || !ntfs_valid_sid(sid))) {
errno = EINVAL;
return NULL;
}
@ -2916,6 +2916,14 @@ int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
if (cached) {
ni->security_id = cached->securid;
NInoSetDirty(ni);
/* adjust Windows read-only flag */
if (!isdir) {
if (mode & S_IWUSR)
ni->flags = le32_and(ni->flags, le32_not(FILE_ATTR_READONLY));
else
ni->flags = le32_or(ni->flags, FILE_ATTR_READONLY);
NInoFileNameSetDirty(ni);
}
}
} else cached = (struct CACHED_SECURID*)NULL;

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2002-2009 Szabolcs Szakacsits
* Copyright (c) 2008-2014 Jean-Pierre Andre
* Copyright (c) 2008-2015 Jean-Pierre Andre
* Copyright (c) 2008 Bernhard Kaindl
*
* This program/include file is free software; you can redistribute it and/or
@ -1128,66 +1128,15 @@ char *ntfs_uppercase_mbs(const char *low,
*/
void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
{
#if 1 /* Vista */
/*
* This is the table as defined by Vista
*/
/*
* "Start" is inclusive and "End" is exclusive, every value has the
* value of "Add" added to it.
*/
static int uc_run_table[][3] = { /* Start, End, Add */
{0x0061, 0x007b, -32}, {0x00e0, 0x00f7, -32}, {0x00f8, 0x00ff, -32},
{0x0256, 0x0258, -205}, {0x028a, 0x028c, -217}, {0x037b, 0x037e, 130},
{0x03ac, 0x03ad, -38}, {0x03ad, 0x03b0, -37}, {0x03b1, 0x03c2, -32},
{0x03c2, 0x03c3, -31}, {0x03c3, 0x03cc, -32}, {0x03cc, 0x03cd, -64},
{0x03cd, 0x03cf, -63}, {0x0430, 0x0450, -32}, {0x0450, 0x0460, -80},
{0x0561, 0x0587, -48}, {0x1f00, 0x1f08, 8}, {0x1f10, 0x1f16, 8},
{0x1f20, 0x1f28, 8}, {0x1f30, 0x1f38, 8}, {0x1f40, 0x1f46, 8},
{0x1f51, 0x1f52, 8}, {0x1f53, 0x1f54, 8}, {0x1f55, 0x1f56, 8},
{0x1f57, 0x1f58, 8}, {0x1f60, 0x1f68, 8}, {0x1f70, 0x1f72, 74},
{0x1f72, 0x1f76, 86}, {0x1f76, 0x1f78, 100}, {0x1f78, 0x1f7a, 128},
{0x1f7a, 0x1f7c, 112}, {0x1f7c, 0x1f7e, 126}, {0x1f80, 0x1f88, 8},
{0x1f90, 0x1f98, 8}, {0x1fa0, 0x1fa8, 8}, {0x1fb0, 0x1fb2, 8},
{0x1fb3, 0x1fb4, 9}, {0x1fcc, 0x1fcd, -9}, {0x1fd0, 0x1fd2, 8},
{0x1fe0, 0x1fe2, 8}, {0x1fe5, 0x1fe6, 7}, {0x1ffc, 0x1ffd, -9},
{0x2170, 0x2180, -16}, {0x24d0, 0x24ea, -26}, {0x2c30, 0x2c5f, -48},
{0x2d00, 0x2d26, -7264}, {0xff41, 0xff5b, -32}, {0}
};
/*
* "Start" is exclusive and "End" is inclusive, every second value is
* decremented by one.
*/
static int uc_dup_table[][2] = { /* Start, End */
{0x0100, 0x012f}, {0x0132, 0x0137}, {0x0139, 0x0149}, {0x014a, 0x0178},
{0x0179, 0x017e}, {0x01a0, 0x01a6}, {0x01b3, 0x01b7}, {0x01cd, 0x01dd},
{0x01de, 0x01ef}, {0x01f4, 0x01f5}, {0x01f8, 0x01f9}, {0x01fa, 0x0220},
{0x0222, 0x0234}, {0x023b, 0x023c}, {0x0241, 0x0242}, {0x0246, 0x024f},
{0x03d8, 0x03ef}, {0x03f7, 0x03f8}, {0x03fa, 0x03fb}, {0x0460, 0x0481},
{0x048a, 0x04bf}, {0x04c1, 0x04c4}, {0x04c5, 0x04c8}, {0x04c9, 0x04ce},
{0x04ec, 0x04ed}, {0x04d0, 0x04eb}, {0x04ee, 0x04f5}, {0x04f6, 0x0513},
{0x1e00, 0x1e95}, {0x1ea0, 0x1ef9}, {0x2183, 0x2184}, {0x2c60, 0x2c61},
{0x2c67, 0x2c6c}, {0x2c75, 0x2c76}, {0x2c80, 0x2ce3}, {0}
};
/*
* Set the Unicode character at offset "Offset" to "Value". Note,
* "Value" is host endian.
*/
static int uc_byte_table[][2] = { /* Offset, Value */
{0x00ff, 0x0178}, {0x0180, 0x0243}, {0x0183, 0x0182}, {0x0185, 0x0184},
{0x0188, 0x0187}, {0x018c, 0x018b}, {0x0192, 0x0191}, {0x0195, 0x01f6},
{0x0199, 0x0198}, {0x019a, 0x023d}, {0x019e, 0x0220}, {0x01a8, 0x01a7},
{0x01ad, 0x01ac}, {0x01b0, 0x01af}, {0x01b9, 0x01b8}, {0x01bd, 0x01bc},
{0x01bf, 0x01f7}, {0x01c6, 0x01c4}, {0x01c9, 0x01c7}, {0x01cc, 0x01ca},
{0x01dd, 0x018e}, {0x01f3, 0x01f1}, {0x023a, 0x2c65}, {0x023e, 0x2c66},
{0x0253, 0x0181}, {0x0254, 0x0186}, {0x0259, 0x018f}, {0x025b, 0x0190},
{0x0260, 0x0193}, {0x0263, 0x0194}, {0x0268, 0x0197}, {0x0269, 0x0196},
{0x026b, 0x2c62}, {0x026f, 0x019c}, {0x0272, 0x019d}, {0x0275, 0x019f},
{0x027d, 0x2c64}, {0x0280, 0x01a6}, {0x0283, 0x01a9}, {0x0288, 0x01ae},
{0x0289, 0x0244}, {0x028c, 0x0245}, {0x0292, 0x01b7}, {0x03f2, 0x03f9},
{0x04cf, 0x04c0}, {0x1d7d, 0x2c63}, {0x214e, 0x2132}, {0}
};
#else /* Vista */
struct NEWUPPERCASE {
unsigned short first;
unsigned short last;
short diff;
unsigned char step;
unsigned char osmajor;
unsigned char osminor;
} ;
/*
* This is the table as defined by Windows XP
*/
@ -1227,9 +1176,88 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
{0}
};
#endif /* Vista */
/*
* Changes which were applied to later Windows versions
*
* md5 for $UpCase from Winxp : 6fa3db2468275286210751e869d36373
* Vista : 2f03b5a69d486ff3864cecbd07f24440
* Win8 : 7ff498a44e45e77374cc7c962b1b92f2
*/
static const struct NEWUPPERCASE newuppercase[] = {
/* from Windows 6.0 (Vista) */
{ 0x37b, 0x37d, 0x82, 1, 6, 0 },
{ 0x1f80, 0x1f87, 0x8, 1, 6, 0 },
{ 0x1f90, 0x1f97, 0x8, 1, 6, 0 },
{ 0x1fa0, 0x1fa7, 0x8, 1, 6, 0 },
{ 0x2c30, 0x2c5e, -0x30, 1, 6, 0 },
{ 0x2d00, 0x2d25, -0x1c60, 1, 6, 0 },
{ 0x2c68, 0x2c6c, -0x1, 2, 6, 0 },
{ 0x219, 0x21f, -0x1, 2, 6, 0 },
{ 0x223, 0x233, -0x1, 2, 6, 0 },
{ 0x247, 0x24f, -0x1, 2, 6, 0 },
{ 0x3d9, 0x3e1, -0x1, 2, 6, 0 },
{ 0x48b, 0x48f, -0x1, 2, 6, 0 },
{ 0x4fb, 0x513, -0x1, 2, 6, 0 },
{ 0x2c81, 0x2ce3, -0x1, 2, 6, 0 },
{ 0x3f8, 0x3fb, -0x1, 3, 6, 0 },
{ 0x4c6, 0x4ce, -0x1, 4, 6, 0 },
{ 0x23c, 0x242, -0x1, 6, 6, 0 },
{ 0x4ed, 0x4f7, -0x1, 10, 6, 0 },
{ 0x450, 0x45d, -0x50, 13, 6, 0 },
{ 0x2c61, 0x2c76, -0x1, 21, 6, 0 },
{ 0x1fcc, 0x1ffc, -0x9, 48, 6, 0 },
{ 0x180, 0x180, 0xc3, 1, 6, 0 },
{ 0x195, 0x195, 0x61, 1, 6, 0 },
{ 0x19a, 0x19a, 0xa3, 1, 6, 0 },
{ 0x19e, 0x19e, 0x82, 1, 6, 0 },
{ 0x1bf, 0x1bf, 0x38, 1, 6, 0 },
{ 0x1f9, 0x1f9, -0x1, 1, 6, 0 },
{ 0x23a, 0x23a, 0x2a2b, 1, 6, 0 },
{ 0x23e, 0x23e, 0x2a28, 1, 6, 0 },
{ 0x26b, 0x26b, 0x29f7, 1, 6, 0 },
{ 0x27d, 0x27d, 0x29e7, 1, 6, 0 },
{ 0x280, 0x280, -0xda, 1, 6, 0 },
{ 0x289, 0x289, -0x45, 1, 6, 0 },
{ 0x28c, 0x28c, -0x47, 1, 6, 0 },
{ 0x3f2, 0x3f2, 0x7, 1, 6, 0 },
{ 0x4cf, 0x4cf, -0xf, 1, 6, 0 },
{ 0x1d7d, 0x1d7d, 0xee6, 1, 6, 0 },
{ 0x1fb3, 0x1fb3, 0x9, 1, 6, 0 },
{ 0x214e, 0x214e, -0x1c, 1, 6, 0 },
{ 0x2184, 0x2184, -0x1, 1, 6, 0 },
/* from Windows 6.1 (Win7) */
{ 0x23a, 0x23e, 0x0, 4, 6, 1 },
{ 0x250, 0x250, 0x2a1f, 2, 6, 1 },
{ 0x251, 0x251, 0x2a1c, 2, 6, 1 },
{ 0x271, 0x271, 0x29fd, 2, 6, 1 },
{ 0x371, 0x373, -0x1, 2, 6, 1 },
{ 0x377, 0x377, -0x1, 2, 6, 1 },
{ 0x3c2, 0x3c2, 0x0, 2, 6, 1 },
{ 0x3d7, 0x3d7, -0x8, 2, 6, 1 },
{ 0x515, 0x523, -0x1, 2, 6, 1 },
{ 0x1d79, 0x1d79, 0x8a04, 2, 6, 1 },
{ 0x1efb, 0x1eff, -0x1, 2, 6, 1 },
{ 0x1fc3, 0x1ff3, 0x9, 48, 6, 1 },
{ 0x1fcc, 0x1ffc, 0x0, 48, 6, 1 },
{ 0x2c65, 0x2c65, -0x2a2b, 2, 6, 1 },
{ 0x2c66, 0x2c66, -0x2a28, 2, 6, 1 },
{ 0x2c73, 0x2c73, -0x1, 2, 6, 1 },
{ 0xa641, 0xa65f, -0x1, 2, 6, 1 },
{ 0xa663, 0xa66d, -0x1, 2, 6, 1 },
{ 0xa681, 0xa697, -0x1, 2, 6, 1 },
{ 0xa723, 0xa72f, -0x1, 2, 6, 1 },
{ 0xa733, 0xa76f, -0x1, 2, 6, 1 },
{ 0xa77a, 0xa77c, -0x1, 2, 6, 1 },
{ 0xa77f, 0xa787, -0x1, 2, 6, 1 },
{ 0xa78c, 0xa78c, -0x1, 2, 6, 1 },
/* end mark */
{ 0 }
} ;
int i, r;
int k, off;
const struct NEWUPPERCASE *puc;
memset((char*)uc, 0, uc_len);
uc_len >>= 1;
@ -1249,6 +1277,16 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
k = uc_byte_table[r][1];
uc[uc_byte_table[r][0]] = cpu_to_le16(k);
}
for (r=0; newuppercase[r].first; r++) {
puc = &newuppercase[r];
if ((puc->osmajor < UPCASE_MAJOR)
|| ((puc->osmajor == UPCASE_MAJOR)
&& (puc->osminor <= UPCASE_MINOR))) {
off = puc->diff;
for (i = puc->first; i <= puc->last; i += puc->step)
uc[i] = cpu_to_le16(i + off);
}
}
}
/*
@ -1533,21 +1571,24 @@ int ntfs_set_char_encoding(const char *locale)
int ntfs_macosx_normalize_filenames(int normalize) {
#ifdef ENABLE_NFCONV
if(normalize == 0 || normalize == 1) {
if (normalize == 0 || normalize == 1) {
nfconvert_utf8 = normalize;
return 0;
}
else
else {
return -1;
}
#else
return -1;
#endif /* ENABLE_NFCONV */
}
int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
int composed) {
int composed)
{
#ifdef ENABLE_NFCONV
/* For this code to compile, the CoreFoundation framework must be fed to the linker. */
/* For this code to compile, the CoreFoundation framework must be fed to
* the linker. */
CFStringRef cfSourceString;
CFMutableStringRef cfMutableString;
CFRange rangeToProcess;
@ -1556,52 +1597,69 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
int resultLength = -1;
/* Convert the UTF-8 string to a CFString. */
cfSourceString = CFStringCreateWithCString(kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8);
if(cfSourceString == NULL) {
cfSourceString = CFStringCreateWithCString(kCFAllocatorDefault,
utf8_string, kCFStringEncodingUTF8);
if (cfSourceString == NULL) {
ntfs_log_error("CFStringCreateWithCString failed!\n");
return -2;
}
/* Create a mutable string from cfSourceString that we are free to modify. */
cfMutableString = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfSourceString);
/* Create a mutable string from cfSourceString that we are free to
* modify. */
cfMutableString = CFStringCreateMutableCopy(kCFAllocatorDefault, 0,
cfSourceString);
CFRelease(cfSourceString); /* End-of-life. */
if(cfMutableString == NULL) {
if (cfMutableString == NULL) {
ntfs_log_error("CFStringCreateMutableCopy failed!\n");
return -3;
}
/* Normalize the mutable string to the desired normalization form. */
CFStringNormalize(cfMutableString, (composed != 0 ? kCFStringNormalizationFormC : kCFStringNormalizationFormD));
/* Store the resulting string in a '\0'-terminated UTF-8 encoded char* buffer. */
CFStringNormalize(cfMutableString, (composed != 0 ?
kCFStringNormalizationFormC : kCFStringNormalizationFormD));
/* Store the resulting string in a '\0'-terminated UTF-8 encoded char*
* buffer. */
rangeToProcess = CFRangeMake(0, CFStringGetLength(cfMutableString));
if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredBufferLength) > 0) {
resultLength = sizeof(char)*(requiredBufferLength + 1);
if (CFStringGetBytes(cfMutableString, rangeToProcess,
kCFStringEncodingUTF8, 0, false, NULL, 0,
&requiredBufferLength) > 0)
{
resultLength = sizeof(char) * (requiredBufferLength + 1);
result = ntfs_calloc(resultLength);
if(result != NULL) {
if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8,
0, false, (UInt8*)result, resultLength-1, &requiredBufferLength) <= 0) {
ntfs_log_error("Could not perform UTF-8 conversion of normalized CFMutableString.\n");
if (result != NULL) {
if (CFStringGetBytes(cfMutableString, rangeToProcess,
kCFStringEncodingUTF8, 0, false,
(UInt8*) result, resultLength - 1,
&requiredBufferLength) <= 0)
{
ntfs_log_error("Could not perform UTF-8 "
"conversion of normalized "
"CFMutableString.\n");
free(result);
result = NULL;
}
}
else
ntfs_log_error("Could not perform a ntfs_calloc of %d bytes for char *result.\n", resultLength);
else {
ntfs_log_error("Could not perform a ntfs_calloc of %d "
"bytes for char *result.\n", resultLength);
}
}
else {
ntfs_log_error("Could not perform check for required length of "
"UTF-8 conversion of normalized CFMutableString.\n");
}
else
ntfs_log_error("Could not perform check for required length of UTF-8 conversion of normalized CFMutableString.\n");
CFRelease(cfMutableString);
if(result != NULL) {
if (result != NULL) {
*target = result;
return resultLength - 1;
}
else
else {
return -1;
}
#else
return -1;
#endif /* ENABLE_NFCONV */

View File

@ -910,6 +910,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
ATTR_RECORD *a;
VOLUME_INFORMATION *vinf;
ntfschar *vname;
u32 record_size;
int i, j, eo;
unsigned int k;
u32 u;
@ -989,7 +990,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
goto io_error_exit;
}
}
if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
record_size = ntfs_mft_record_get_data_size(mrec);
if ((record_size <= sizeof(MFT_RECORD))
|| (record_size > vol->mft_record_size)
|| memcmp(mrec, mrec2, record_size)) {
ntfs_log_error("$MFTMirr does not match $MFT (record "
"%d).\n", i);
goto io_error_exit;

View File

@ -1881,7 +1881,11 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
#ifdef BLKSSZGET
case BLKSSZGET:
ntfs_log_debug("BLKSSZGET detected.\n");
return ntfs_win32_blksszget(dev, (int *)argp);
if (fd && !fd->ntdll) {
*(int*)argp = fd->geo_sector_size;
return (0);
} else
return ntfs_win32_blksszget(dev, (int *)argp);
#endif
#ifdef BLKBSZSET
case BLKBSZSET:

View File

@ -17,7 +17,7 @@ if ENABLE_NTFSPROGS
bin_PROGRAMS = ntfsfix ntfsinfo ntfscluster ntfsls ntfscat ntfscmp
sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize ntfsclone \
ntfscp
EXTRA_PROGRAM_NAMES = ntfswipe ntfstruncate
EXTRA_PROGRAM_NAMES = ntfswipe ntfstruncate ntfsrecover
QUARANTINED_PROGRAM_NAMES = ntfsdump_logfile ntfsmftalloc ntfsmove ntfsck \
ntfsfallocate
@ -26,7 +26,7 @@ man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8 \
ntfsundelete.8 ntfsresize.8 ntfsprogs.8 ntfsls.8 \
ntfsclone.8 ntfscluster.8 ntfscat.8 ntfscp.8 \
ntfscmp.8 ntfswipe.8 ntfstruncate.8 \
ntfsdecrypt.8 ntfsfallocate.8
ntfsdecrypt.8 ntfsfallocate.8 ntfsrecover.8
EXTRA_MANS =
CLEANFILES = $(EXTRA_PROGRAMS)
@ -102,6 +102,10 @@ ntfscmp_SOURCES = ntfscmp.c utils.c utils.h
ntfscmp_LDADD = $(AM_LIBS)
ntfscmp_LDFLAGS = $(AM_LFLAGS)
ntfsrecover_SOURCES = playlog.c ntfsrecover.c utils.c utils.h ntfsrecover.h
ntfsrecover_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS)
ntfsrecover_LDFLAGS = $(AM_LFLAGS)
# We don't distribute these
ntfstruncate_SOURCES = attrdef.c ntfstruncate.c utils.c utils.h
@ -149,6 +153,7 @@ extras: libs $(EXTRA_PROGRAMS)
# mkfs.ntfs[.8] hard link
if ENABLE_MOUNT_HELPER
install-exec-hook:
$(INSTALL) -d $(DESTDIR)/sbin
$(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)/sbin/mkfs.ntfs
@ -160,5 +165,6 @@ install-data-hook:
uninstall-local:
$(RM) -f $(DESTDIR)/sbin/mkfs.ntfs
$(RM) -f $(DESTDIR)$(man8dir)/mkfs.ntfs.8
endif
endif

View File

@ -156,7 +156,9 @@ omitted,
.B mkntfs
attempts to determine
.I part\-start\-sect
automatically and if that fails a default of 0 is used. Note that
automatically and if that fails or the value is oversized, a
default of 0 is used. The partition is usable despite a wrong value,
however note that a correct
.I part\-start\-sect
is required for Windows to be able to boot from the created volume.
.TP

View File

@ -3636,10 +3636,12 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol)
opts.part_start_sect = 0;
winboot = FALSE;
} else if (opts.part_start_sect >> 32) {
ntfs_log_warning("The partition start sector specified "
"for %s and the automatically determined value "
"is too large. It has been set to 0.\n",
vol->dev->d_name);
ntfs_log_warning("The partition start sector was not "
"specified for %s and the automatically "
"determined value is too large (%lld). "
"It has been set to 0.\n",
vol->dev->d_name,
(long long)opts.part_start_sect);
opts.part_start_sect = 0;
winboot = FALSE;
}

View File

@ -423,8 +423,21 @@ int main(int argc, char *argv[])
if (opts.inode != -1)
inode = ntfs_inode_open(vol, opts.inode);
else
else {
#ifdef HAVE_WINDOWS_H
char *unix_name;
unix_name = ntfs_utils_unix_path(opts.file);
if (unix_name) {
inode = ntfs_pathname_to_inode(vol, NULL,
unix_name);
free(unix_name);
} else
inode = (ntfs_inode*)NULL;
#else
inode = ntfs_pathname_to_inode(vol, NULL, opts.file);
#endif
}
if (!inode) {
ntfs_log_perror("ERROR: Couldn't open inode");

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2003-2006 Szabolcs Szakacsits
* Copyright (c) 2004-2006 Anton Altaparmakov
* Copyright (c) 2010-2014 Jean-Pierre Andre
* Copyright (c) 2010-2015 Jean-Pierre Andre
* Special image format support copyright (c) 2004 Per Olofsson
*
* Clone NTFS data and/or metadata to a sparse file, image, device or stdout.
@ -391,7 +391,7 @@ static void version(void)
"Efficiently clone, image, restore or rescue an NTFS Volume.\n\n"
"Copyright (c) 2003-2006 Szabolcs Szakacsits\n"
"Copyright (c) 2004-2006 Anton Altaparmakov\n"
"Copyright (c) 2010-2014 Jean-Pierre Andre\n\n");
"Copyright (c) 2010-2015 Jean-Pierre Andre\n\n");
fprintf(stderr, "%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
exit(0);
}
@ -2458,64 +2458,27 @@ static void check_output_device(s64 input_size)
set_filesize(input_size);
}
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_printf("ntfs_attr_get_search_ctx");
return ret;
}
/**
* lookup_data_attr
*
* Find the $DATA attribute (with or without a name) for the given ntfs inode.
*/
static ntfs_attr_search_ctx *lookup_data_attr(ntfs_inode *ni, const char *aname)
{
ntfs_attr_search_ctx *ctx;
ntfschar *ustr;
int len = 0;
if ((ctx = attr_get_search_ctx(ni)) == NULL)
return NULL;
if ((ustr = ntfs_str2ucs(aname, &len)) == NULL) {
perr_printf("Couldn't convert '%s' to Unicode", aname);
goto error_out;
}
if (ntfs_attr_lookup(AT_DATA, ustr, len, CASE_SENSITIVE,
0, NULL, 0, ctx)) {
perr_printf("ntfs_attr_lookup");
goto error_out;
}
ntfs_ucsfree(ustr);
return ctx;
error_out:
ntfs_attr_put_search_ctx(ctx);
return NULL;
}
static void ignore_bad_clusters(ntfs_walk_clusters_ctx *image)
{
ntfs_inode *ni;
ntfs_attr_search_ctx *ctx = NULL;
runlist *rl, *rl_bad;
ntfs_attr *na;
runlist *rl;
s64 nr_bad_clusters = 0;
static le16 Bad[4] = {
const_cpu_to_le16('$'), const_cpu_to_le16('B'),
const_cpu_to_le16('a'), const_cpu_to_le16('d')
} ;
if (!(ni = ntfs_inode_open(vol, FILE_BadClus)))
perr_exit("ntfs_open_inode");
if ((ctx = lookup_data_attr(ni, "$Bad")) == NULL)
exit(1);
na = ntfs_attr_open(ni, AT_DATA, Bad, 4);
if (!na)
perr_exit("ntfs_attr_open");
if (ntfs_attr_map_whole_runlist(na))
perr_exit("ntfs_attr_map_whole_runlist");
if (!(rl_bad = ntfs_mapping_pairs_decompress(vol, ctx->attr, NULL)))
perr_exit("ntfs_mapping_pairs_decompress");
for (rl = rl_bad; rl->length; rl++) {
for (rl = na->rl; rl->length; rl++) {
s64 lcn = rl->lcn;
if (lcn == LCN_HOLE || lcn < 0)
@ -2529,9 +2492,7 @@ static void ignore_bad_clusters(ntfs_walk_clusters_ctx *image)
if (nr_bad_clusters)
Printf("WARNING: The disk has %lld or more bad sectors"
" (hardware faults).\n", (long long)nr_bad_clusters);
free(rl_bad);
ntfs_attr_put_search_ctx(ctx);
ntfs_attr_close(na);
if (ntfs_inode_close(ni))
perr_exit("ntfs_inode_close failed for $BadClus");
}

View File

@ -834,6 +834,9 @@ int main(int argc, char *argv[])
s64 br, bw;
ntfschar *attr_name;
int attr_name_len = 0;
#ifdef HAVE_WINDOWS_H
char *unix_name;
#endif
ntfs_log_set_handler(ntfs_log_handler_stderr);
@ -900,8 +903,17 @@ int main(int argc, char *argv[])
goto close_src;
}
out = ntfs_inode_open(vol, inode_num);
} else
} else {
#ifdef HAVE_WINDOWS_H
unix_name = ntfs_utils_unix_path(opts.dest_file);
if (unix_name) {
out = ntfs_pathname_to_inode(vol, NULL, unix_name);
} else
out = (ntfs_inode*)NULL;
#else
out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file);
#endif
}
if (!out) {
/* Copy the file if the dest_file's parent dir can be opened. */
char *parent_dirname;
@ -910,8 +922,13 @@ int main(int argc, char *argv[])
ntfs_inode *ni;
char *dirname_last_whack;
#ifdef HAVE_WINDOWS_H
filename = basename(unix_name);
parent_dirname = strdup(unix_name);
#else
filename = basename(opts.dest_file);
parent_dirname = strdup(opts.dest_file);
#endif
if (!parent_dirname) {
ntfs_log_perror("strdup() failed");
goto close_src;
@ -983,8 +1000,12 @@ int main(int argc, char *argv[])
ntfs_inode_close(out);
goto close_src;
}
#ifdef HAVE_WINDOWS_H
strcpy(overwrite_filename, unix_name);
#else
strcpy(overwrite_filename, opts.dest_file);
if (opts.dest_file[dest_dirname_len - 1] != '/') {
#endif
if (overwrite_filename[dest_dirname_len - 1] != '/') {
strcat(overwrite_filename, "/");
}
strcat(overwrite_filename, filename);

View File

@ -4,7 +4,7 @@
* Copyright (c) 2005 Yuval Fledel
* Copyright (c) 2005-2007 Anton Altaparmakov
* Copyright (c) 2007 Yura Pakhuchiy
* Copyright (c) 2014 Jean-Pierre Andre
* Copyright (c) 2014-2015 Jean-Pierre Andre
*
* This utility will decrypt files and print the decrypted data on the standard
* output.
@ -117,6 +117,7 @@ typedef enum {
typedef struct {
u64 in_whitening, out_whitening;
u8 des_key[8];
u64 prev_blk;
} ntfs_desx_ctx;
/**
@ -164,7 +165,7 @@ static void version(void)
"standard output.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c) 2005 Yuval Fledel\n");
ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n");
ntfs_log_info("Copyright (c) 2014 Jean-Pierre Andre\n");
ntfs_log_info("Copyright (c) 2014-2015 Jean-Pierre Andre\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -895,39 +896,39 @@ out:
/**
* ntfs_desx_decrypt
*/
static void ntfs_desx_decrypt(ntfs_fek *fek, u8 *outbuf, const u8 *inbuf)
static gcry_error_t ntfs_desx_decrypt(ntfs_fek *fek, u8 *outbuf,
const u8 *inbuf)
{
gcry_error_t err;
u64 curr_blk;
ntfs_desx_ctx *ctx = &fek->desx_ctx;
err = gcry_cipher_reset(fek->gcry_cipher_hd);
if (err != GPG_ERR_NO_ERROR)
ntfs_log_error("Failed to reset des cipher (error 0x%x).\n",
err);
*(u64*)outbuf = *(const u64*)inbuf ^ ctx->out_whitening;
curr_blk = *(const u64*)inbuf;
*(u64*)outbuf = curr_blk ^ ctx->out_whitening;
err = gcry_cipher_encrypt(fek->gcry_cipher_hd, outbuf, 8, NULL, 0);
if (err != GPG_ERR_NO_ERROR)
ntfs_log_error("Des decryption failed (error 0x%x).\n", err);
*(u64*)outbuf ^= ctx->in_whitening;
*(u64*)outbuf ^= ctx->in_whitening ^ ctx->prev_blk;
ctx->prev_blk = curr_blk;
return (err);
}
/**
* ntfs_desx_encrypt
*/
static void ntfs_desx_encrypt(ntfs_fek *fek, u8 *outbuf, const u8 *inbuf)
static gcry_error_t ntfs_desx_encrypt(ntfs_fek *fek, u8 *outbuf,
const u8 *inbuf)
{
gcry_error_t err;
ntfs_desx_ctx *ctx = &fek->desx_ctx;
err = gcry_cipher_reset(fek->gcry_cipher_hd);
if (err != GPG_ERR_NO_ERROR)
ntfs_log_error("Failed to reset des cipher (error 0x%x).\n",
err);
*(u64*)outbuf = *(const u64*)inbuf ^ ctx->in_whitening;
*(u64*)outbuf = *(const u64*)inbuf ^ ctx->in_whitening ^ ctx->prev_blk;
err = gcry_cipher_decrypt(fek->gcry_cipher_hd, outbuf, 8, NULL, 0);
if (err != GPG_ERR_NO_ERROR)
ntfs_log_error("Des decryption failed (error 0x%x).\n", err);
*(u64*)outbuf ^= ctx->out_whitening;
ctx->prev_blk = *(u64*)outbuf;
return (err);
}
//#define DO_CRYPTO_TESTS 1
@ -1300,8 +1301,9 @@ static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset)
if (le32_eq(fek->alg_id, CALG_DESX)) {
int k;
for (k=0; k<512; k+=8) {
ntfs_desx_decrypt(fek, &data[k], &data[k]);
fek->desx_ctx.prev_blk = 0;
for (k=0; (k < 512) && (err == GPG_ERR_NO_ERROR); k+=8) {
err = ntfs_desx_decrypt(fek, &data[k], &data[k]);
}
} else
err = gcry_cipher_decrypt(fek->gcry_cipher_hd, data, 512, NULL, 0);
@ -1350,8 +1352,9 @@ static int ntfs_fek_encrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset)
if (le32_eq(fek->alg_id, CALG_DESX)) {
int k;
for (k=0; k<512; k+=8) {
ntfs_desx_encrypt(fek, &data[k], &data[k]);
fek->desx_ctx.prev_blk = 0;
for (k=0; (k < 512) && (err == GPG_ERR_NO_ERROR); k+=8) {
err = ntfs_desx_encrypt(fek, &data[k], &data[k]);
}
} else
err = gcry_cipher_encrypt(fek->gcry_cipher_hd, data, 512, NULL, 0);

View File

@ -859,15 +859,8 @@ int main(int argc, char **argv)
/* Open the specified inode. */
#ifdef HAVE_WINDOWS_H
unix_name = (char*)malloc(strlen(file_name) + 1);
unix_name = ntfs_utils_unix_path(file_name);
if (unix_name) {
int i;
for (i=0; file_name[i]; i++)
if (file_name[i] == '\\')
unix_name[i] = '/';
else
unix_name[i] = file_name[i];
unix_name[i] = 0;
ni = ntfs_pathname_to_inode(vol, NULL, unix_name);
free(unix_name);
} else

View File

@ -4,7 +4,7 @@
* Copyright (c) 2000-2006 Anton Altaparmakov
* Copyright (c) 2002-2006 Szabolcs Szakacsits
* Copyright (c) 2007 Yura Pakhuchiy
* Copyright (c) 2011-2014 Jean-Pierre Andre
* Copyright (c) 2011-2015 Jean-Pierre Andre
*
* This utility fixes some common NTFS problems, resets the NTFS journal file
* and schedules an NTFS consistency check for the first boot into Windows.
@ -154,7 +154,7 @@ static void version(void)
"Copyright (c) 2000-2006 Anton Altaparmakov\n"
"Copyright (c) 2002-2006 Szabolcs Szakacsits\n"
"Copyright (c) 2007 Yura Pakhuchiy\n"
"Copyright (c) 2011-2014 Jean-Pierre Andre\n\n",
"Copyright (c) 2011-2015 Jean-Pierre Andre\n\n",
EXEC_NAME, VERSION);
ntfs_log_info("%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
exit(0);
@ -739,13 +739,14 @@ static ATTR_RECORD *find_unnamed_attr(MFT_RECORD *mrec, ATTR_TYPES type)
/* fetch the requested attribute */
offset = le16_to_cpu(mrec->attrs_offset);
a = (ATTR_RECORD*)((char*)mrec + offset);
while (!le32_eq(a->type, AT_END)
&& (!le32_eq(a->type, type) || a->name_length)
&& (offset < le32_to_cpu(mrec->bytes_in_use))) {
while ((offset < le32_to_cpu(mrec->bytes_in_use))
&& !le32_eq(a->type, AT_END)
&& (!le32_eq(a->type, type) || a->name_length)) {
offset += le32_to_cpu(a->length);
a = (ATTR_RECORD*)((char*)mrec + offset);
}
if (!le32_eq(a->type, type)
if ((offset >= le32_to_cpu(mrec->bytes_in_use))
|| !le32_eq(a->type, type)
|| a->name_length)
a = (ATTR_RECORD*)NULL;
return (a);
@ -1117,9 +1118,10 @@ static int fix_selfloc_conditions(struct MFT_SELF_LOCATED *selfloc)
*
* Only low-level library functions can be used.
*
* Returns 0 if the conditions for the error were not met or
* the error could be fixed,
* -1 if some error was encountered
* Returns 0 if the conditions for the error was met and
* this error could be fixed,
* -1 if the condition was not met or some error
* which could not be fixed was encountered.
*/
static int fix_self_located_mft(ntfs_volume *vol)
@ -1146,7 +1148,7 @@ static int fix_self_located_mft(ntfs_volume *vol)
ntfs_log_info(res ? FAILED : OK);
} else {
ntfs_log_info(OK);
res = 0;
res = -1;
}
free(selfloc.mft0);
free(selfloc.mft1);
@ -1377,6 +1379,8 @@ error_exit :
*
* This is a replay of the normal start up sequence with fixes when
* some problem arise.
*
* Returns 0 if there was an error and a fix is available
*/
static int fix_startup(struct ntfs_device *dev, unsigned long flags)
@ -1646,8 +1650,10 @@ int main(int argc, char **argv)
/* Set return code to 0. */
ret = 0;
error_exit:
if (ntfs_umount(vol, 0))
ntfs_umount(vol, 1);
if (ntfs_umount(vol, 1)) {
ntfs_log_info("Failed to unmount partition\n");
ret = 1;
}
if (ret)
exit(ret);
return ret;

View File

@ -8,7 +8,7 @@
* Copyright (c) 2004-2005 Yuval Fledel
* Copyright (c) 2004-2007 Yura Pakhuchiy
* Copyright (c) 2005 Cristian Klein
* Copyright (c) 2011-2014 Jean-Pierre Andre
* Copyright (c) 2011-2015 Jean-Pierre Andre
*
* This utility will dump a file's attributes.
*
@ -408,6 +408,22 @@ static char *ntfs_attr_get_name_mbs(ATTR_RECORD *attr)
return NULL;
}
static const char *reparse_type_name(le32 tag)
{
const char *name;
if (le32_eq(tag, IO_REPARSE_TAG_MOUNT_POINT))
name = " (mount point)";
else
if (le32_eq(tag, IO_REPARSE_TAG_SYMLINK))
name = " (symlink)";
else
if (le32_eq(tag, IO_REPARSE_TAG_WOF))
name = " (Wof compressed)";
else
name = "";
return (name);
}
/* *************** functions for dumping global info ******************** */
/**
@ -776,6 +792,8 @@ static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol)
static void ntfs_dump_filename(const char *indent,
FILE_NAME_ATTR *file_name_attr)
{
le32 tag;
printf("%sParent directory:\t %lld (0x%llx)\n", indent,
(long long)MREF_LE(file_name_attr->parent_directory),
(long long)MREF_LE(file_name_attr->parent_directory));
@ -813,10 +831,12 @@ static void ntfs_dump_filename(const char *indent,
(unsigned)file_name_attr->file_name_length);
ntfs_dump_flags(indent, AT_FILE_NAME, file_name_attr->file_attributes);
if (!le32_andz(file_name_attr->file_attributes, FILE_ATTR_REPARSE_POINT) &&
!le32_cmpz(file_name_attr->reparse_point_tag))
printf("%sReparse point tag:\t 0x%x\n", indent, (unsigned)
le32_to_cpu(file_name_attr->reparse_point_tag));
else if (!le32_cmpz(file_name_attr->reparse_point_tag)) {
!le32_cmpz(file_name_attr->reparse_point_tag)) {
tag = file_name_attr->reparse_point_tag;
printf("%sReparse point tag:\t 0x%08lx%s\n", indent,
(long)le32_to_cpu(tag),
reparse_type_name(tag));
} else if (!le32_cmpz(file_name_attr->reparse_point_tag)) {
printf("%sEA Length:\t\t %d (0x%x)\n", indent, (unsigned)
le16_to_cpu(file_name_attr->packed_ea_size),
(unsigned)
@ -1431,6 +1451,7 @@ static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type)
{
char *sid;
char printable_GUID[37];
le32 tag;
switch (type) {
case INDEX_ATTR_SECURE_SII:
@ -1454,8 +1475,10 @@ static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type)
ntfs_log_verbose("\t\tKey GUID:\t\t %s\n", printable_GUID);
break;
case INDEX_ATTR_REPARSE_R:
ntfs_log_verbose("\t\tKey reparse tag:\t 0x%08x\n", (unsigned)
le32_to_cpu(entry->key.reparse.reparse_tag));
tag = entry->key.reparse.reparse_tag;
ntfs_log_verbose("\t\tKey reparse tag:\t 0x%08lx%s\n",
(long)le32_to_cpu(tag),
reparse_type_name(tag));
ntfs_log_verbose("\t\tKey file id:\t\t %llu (0x%llx)\n",
(unsigned long long)
le64_to_cpu(entry->key.reparse.file_id),
@ -1946,9 +1969,49 @@ static void ntfs_dump_attr_bitmap(ATTR_RECORD *attr __attribute__((unused)))
*
* of ntfs 3.x dumps the reparse_point attribute
*/
static void ntfs_dump_attr_reparse_point(ATTR_RECORD *attr __attribute__((unused)))
static void ntfs_dump_attr_reparse_point(ATTR_RECORD *attr
__attribute__((unused)), ntfs_inode *inode)
{
/* TODO */
REPARSE_POINT *reparse;
le32 tag;
const char *name;
u8 *pvalue;
s64 size;
unsigned int length;
unsigned int cnt;
if (attr->non_resident) {
reparse = ntfs_attr_readall(inode, AT_REPARSE_POINT,
(ntfschar*)NULL, 0, &size);
} else {
reparse = (REPARSE_POINT*)((u8*)attr +
le16_to_cpu(attr->value_offset));
}
if (reparse) {
tag = reparse->reparse_tag;
name = reparse_type_name(tag);
printf("\tReparse tag:\t\t 0x%08lx%s\n",
(long)le32_to_cpu(tag),name);
length = le16_to_cpu(reparse->reparse_data_length);
printf("\tData length:\t\t %u (0x%x)\n",
(unsigned int)length,(unsigned int)length);
cnt = length;
pvalue = reparse->reparse_data;
printf("\tData:\t\t\t");
printf(cnt ? " 0x" : "(NONE)");
if (cnt > 32)
cnt = 32;
while (cnt-- > 0)
printf("%02x",*pvalue++);
if (length > 32)
printf("...\n");
else
printf("\n");
if (attr->non_resident)
free(reparse);
} else {
ntfs_log_perror("Failed to get the reparse data");
}
}
/**
@ -2300,7 +2363,7 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode)
ntfs_dump_attr_bitmap(ctx->attr);
}
else if (le32_eq(ctx->attr->type, AT_REPARSE_POINT)) {
ntfs_dump_attr_reparse_point(ctx->attr);
ntfs_dump_attr_reparse_point(ctx->attr, inode);
}
else if (le32_eq(ctx->attr->type, AT_EA_INFORMATION)) {
ntfs_dump_attr_ea_information(ctx->attr);
@ -2379,8 +2442,20 @@ int main(int argc, char **argv)
ntfs_inode *inode;
/* obtain the inode */
if (opts.filename) {
#ifdef HAVE_WINDOWS_H
char *unix_name;
unix_name = ntfs_utils_unix_path(opts.filename);
if (unix_name) {
inode = ntfs_pathname_to_inode(vol, NULL,
unix_name);
free(unix_name);
} else
inode = (ntfs_inode*)NULL;
#else
inode = ntfs_pathname_to_inode(vol, NULL,
opts.filename);
#endif
} else {
inode = ntfs_inode_open(vol, MK_MREF(opts.inode, 0));
}

View File

@ -0,0 +1,165 @@
.\" Copyright (c) 2015 Jean-Pierre Andre
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSRECOVER 8 "September 2015" "ntfs-3g @VERSION@"
.SH NAME
ntfsrecover \- Recover updates committed by Windows on an NTFS volume
.SH SYNOPSIS
\fBntfsrecover\fR [\fIoptions\fR] \fIdevice\fR
.SH DESCRIPTION
.B ntfsrecover
applies to the metadata the updates which were requested on Windows but could
not be completed because they were interrupted by some event such as a power
failure, a hardware crash, a software crash or the device being unplugged.
Doing so, the file system is restored to a consistent state, however updates
to user data may still be lost.
Updating the file system generally requires updating several records which
should all be made for the file system to be kept consistent. For instance,
creating a new file requires reserving an inode number (set a bit in a bit
map), creating a file record (store the file name and file attributes), and
registering the file in a directory (locate the file from some path). When an
unfortunate event occurs, and one of these updates could be done but not all
of them, the file system is left inconsistent.
A group of updates which have all to be done to preserve consistency is
called a transaction, and the end of updates within a transaction is called
the commitment of the transaction.
To protect from unfortunate events, Windows first logs in a special file all
the metadata update requests without applying any, until the commitment is
known. If the event occurs before the commitment, no update has been made and
the file system is consistent. If the event occurs after the update, the log
file can be analyzed later and the transactions which were committed can be
executed again, thus restoring the integrity of the file system.
.B ntfsrecover
similarly examines the log file and applies the updates within committed
transactions which could not be done by Windows.
Currently, ntfs-3g does not log updates, so
.B ntfsrecover
cannot be used to restore consistency after an unfortunate event occurred
while the file system was updated by Linux.
.SH OPTIONS
Below is a summary of all the options that
.B ntfsrecover
accepts. The normal usage is to use no option at all, as most of these
options are oriented towards developers needs.
Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-bv
is equivalent to
.BR "\-b \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-b\fR, \fB\-\-backward\fR
Examine the actions described in the logfile backward from the latest one to
the earliest one without applying any update. This may encompass records
generated during several sessions, and when Windows is restarted, it often
does not restart writing where it ended the previous session, so this leads
to errors and bad sequencing when examining the full log file.
.TP
\fB\-c\fR, \fB\-\-clusters\fR \fBCLUSTER-RANGE\fR
Restrict the output generated when using options -b -f -u -p
to the actions operating on a cluster within the given cluster range.
CLUSTER-RANGE is defined by the first and last cluster numbers separated
by a hyphen, for instance 100-109 or 0x3e8-0x3ff. A single number means
restricting to a single cluster. The first four log blocks have a special
role and they are always shown.
.TP
\fB\-f\fR, \fB\-\-forward\fR \fBNUM\fR
Examine the actions described in the logfile forward from the first one to
the last one without applying any update. As the log file is reused
circularly, the first one is generally not the earliest. Moreover when
Windows is restarted, it often does not restart writing where it ended the
previous sessions, and this leads to errors when examining a log file
generated during several sessions.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show some help information.
.TP
\fB\-n\fR, \fB\-\-no-action\fR
Do not apply any modification, useful when using the options -p, -s or -u.
.TP
\fB\-p\fR, \fB\-\-play\fR \fBCOUNT\fR
Undo COUNT transaction sets and redo a single one, a transaction set being
all transactions between two consecutive checkpoints. This is useful for
replaying some transaction in the past. As a few actions are not undoable,
this is not always possible.
.TP
\fB\-r\fR, \fB\-\-range\fR \fBBLOCK-RANGE\fR
Examine the actions described in the logfile forward restricted to the
requested log file block range without applying any update. The first four
log blocks have a special role and they are always examined.
.TP
\fB\-s\fR, \fB\-\-sync\fR
Sync the file system by applying the committed actions which have not
been synced previously. This is the default option, used when none of
the options -n, -f, -r, -p and -u are present.
The option -s can be repeated to request applying the committed actions
mentioned in the obsolete restart page. This is useful for testing the
situations where the latest restart page cannot be read though it can
actually be read.
.TP
\fB\-t\fR, \fB\-\-transactions\fR \fBCOUNT\fR
Display the transaction parameters when examining the log file with one
of the options --forward, --backward or --range.
.TP
\fB\-u\fR, \fB\-\-undo\fR \fBCOUNT\fR
Undo COUNT transaction sets, thus resetting the file system to some
checkpoint in the past, a transaction set being all transactions between
two consecutive checkpoints. As a few actions are not undoable, this is
not always possible.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Display more debug/warning/error messages. This option may be used twice
to display even more information.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license of
.BR ntfsrecover .
.SH EXAMPLES
Sync an NTFS volume on /dev/sda1.
.RS
.sp
.B ntfsrecover -s /dev/sda1
.sp
.RE
Display all actions which updated a cluster in range 100 to 119 :
.RS
.sp
.B ntfsrecover --verbose --backward --clusters=100-119 /dev/sda1
.sp
.RE
.SH BUGS
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
ntfs\-3g\-devel@lists.sf.net
.hy
.SH AUTHORS
.B ntfsrecover
was written by Jean-Pierre Andre
.SH AVAILABILITY
.B ntfsrecover
is part of the
.B ntfs-3g
package and is available from:
.br
.nh
http://www.tuxera.com/community/
.hy
.SH SEE ALSO
.BR ntfs-3g (8),
.BR ntfsfix (8),
.BR ntfsprogs (8)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,339 @@
/*
* Declarations for processing log data
*
* Copyright (c) 2000-2005 Anton Altaparmakov
* Copyright (c) 2014-2015 Jean-Pierre Andre
*/
/*
* 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 NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* TODO
* This file partially duplicates logfile.h (with modifications).
* The generic declarations are to be moved to logfile.h, thus
* implying adapting (at least) libntfs-3g/logfile.c and
* ntfsprogs/ntfsdump_logfile.c, and the declarations specific to
* ntfsrecover should be kept in this file.
* (removing ntfsdump_logfile.c might also be considered).
*/
#define getle16(p,x) le16_to_cpu(*(const le16*)((const char*)(p) + (x)))
#define getle32(p,x) le32_to_cpu(*(const le32*)((const char*)(p) + (x)))
#define getle64(p,x) le64_to_cpu(*(const le64*)((const char*)(p) + (x)))
#define feedle16(p,x) (*(const le16*)((const char*)(p) + (x)))
#define feedle32(p,x) (*(const le32*)((const char*)(p) + (x)))
#define feedle64(p,x) (*(const le64*)((const char*)(p) + (x)))
enum LOG_RECORD_TYPE {
LOG_STANDARD = 1,
LOG_CHECKPOINT = 2
} ;
/* These flags were introduced in Vista in field attribute_flags */
enum ATTRIBUTE_FLAGS {
ACTS_ON_MFT = 2,
ACTS_ON_INDX = 8
} ;
enum ACTIONS {
Noop, /* 0 */
CompensationlogRecord, /* 1 */
InitializeFileRecordSegment, /* 2 */
DeallocateFileRecordSegment, /* 3 */
WriteEndofFileRecordSegment, /* 4 */
CreateAttribute, /* 5 */
DeleteAttribute, /* 6 */
UpdateResidentValue, /* 7 */
UpdateNonResidentValue, /* 8 */
UpdateMappingPairs, /* 9 */
DeleteDirtyClusters, /* 10 */
SetNewAttributeSizes, /* 11 */
AddIndexEntryRoot, /* 12 */
DeleteIndexEntryRoot, /* 13 */
AddIndexEntryAllocation, /* 14 */
DeleteIndexEntryAllocation, /* 15 */
WriteEndOfIndexBuffer, /* 16 */
SetIndexEntryVcnRoot, /* 17 */
SetIndexEntryVcnAllocation, /* 18 */
UpdateFileNameRoot, /* 19 */
UpdateFileNameAllocation, /* 20 */
SetBitsInNonResidentBitMap, /* 21 */
ClearBitsInNonResidentBitMap, /* 22 */
HotFix, /* 23 */
EndTopLevelAction, /* 24 */
PrepareTransaction, /* 25 */
CommitTransaction, /* 26 */
ForgetTransaction, /* 27 */
OpenNonResidentAttribute, /* 28 */
OpenAttributeTableDump, /* 29 */
AttributeNamesDump, /* 30 */
DirtyPageTableDump, /* 31 */
TransactionTableDump, /* 32 */
UpdateRecordDataRoot, /* 33 */
UpdateRecordDataAllocation, /* 34 */
Win10Action35, /* 35 */
Win10Action36, /* 36 */
Win10Action37, /* 37 */
LastAction /* 38 */
} ;
/* Flags for field log_record_flags, their meaning is unclear */
enum RECORD_FLAGS {
RECORD_UNKNOWN = 1,
/* The flags below were introduced in Windows 10 */
RECORD_DELETING = 2,
RECORD_ADDING = 4
} ;
typedef le16 LOG_RECORD_FLAGS;
#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff)
#define RESTART_VOLUME_IS_CLEAN const_cpu_to_le16(0x0002)
/* ntfsdoc p 39 (47), not in layout.h */
typedef struct RESTART_PAGE_HEADER { /* size 32 */
NTFS_RECORD head;
leLSN chkdsk_lsn;
le32 system_page_size;
le32 log_page_size;
le16 restart_offset;
le16 minor_ver;
le16 major_ver;
le16 usn;
} __attribute__((__packed__)) RESTART_PAGE_HEADER;
/* ntfsdoc p 40 (48), not in layout.h */
struct RESTART_AREA { /* size 44 */
leLSN current_lsn;
le16 log_clients;
le16 client_free_list;
le16 client_in_use_list;
le16 flags;
le32 seq_number_bits;
le16 restart_area_length;
le16 client_array_offset;
le64 file_size;
le32 last_lsn_data_length;
le16 record_length;
le16 log_page_data_offset;
le32 restart_log_open_count;
} __attribute__((__packed__)) ;
typedef struct RESTART_CLIENT { /* size 160 */
/*Ofs*/
/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
set to 0. */
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
the volume, i.e. the current position within
the log file. At present, if clean this
should = current_lsn in restart area but it
probably also = current_lsn when dirty most
of the time. At create set to 0. */
/* 16*/ le16 prev_client; /* The offset to the previous log client record
in the array of log client records.
LOGFILE_NO_CLIENT means there is no previous
client record, i.e. this is the first one.
This is always LOGFILE_NO_CLIENT. */
/* 18*/ le16 next_client; /* The offset to the next log client record in
the array of log client records.
LOGFILE_NO_CLIENT means there are no next
client records, i.e. this is the last one.
This is always LOGFILE_NO_CLIENT. */
/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set
to zero every time the logfile is restarted
and it is incremented when the logfile is
closed at dismount time. Thus it is 0 when
dirty and 1 when clean. On WinXP and
presumably later, this is always 0. */
/* 22*/ u8 reserved[6]; /* Reserved/alignment. */
/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should
always be 8. */
/* 32*/ le16 client_name[64]; /* Name of the client in Unicode. Should
always be "NTFS" with the remaining bytes
set to 0. */
/* sizeof() = 160 (0xa0) bytes */
} __attribute__((__packed__)) LOG_CLIENT_RECORD;
/* ntfsdoc p 41 (49), not in layout.h */
struct RECORD_PAGE_HEADER { /* size 40 */
NTFS_RECORD head; /* the magic is "RCRD" */
union {
leLSN last_lsn;
le32 file_offset;
} __attribute__((__packed__)) copy;
le32 flags;
le16 page_count;
le16 page_position;
le16 next_record_offset;
le16 reserved4[3];
leLSN last_end_lsn;
} __attribute__((__packed__)) ;
/* ntfsdoc p 42 (50), not in layout.h */
#define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */
typedef struct LOG_RECORD { /* size 80 */
leLSN this_lsn;
leLSN client_previous_lsn;
leLSN client_undo_next_lsn;
le32 client_data_length;
struct {
le16 seq_number;
le16 client_index;
} __attribute__((__packed__)) client_id;
le32 record_type;
le32 transaction_id;
LOG_RECORD_FLAGS log_record_flags;
le16 reserved1[3];
le16 redo_operation;
le16 undo_operation;
le16 redo_offset;
le16 redo_length;
union {
struct {
le16 undo_offset;
le16 undo_length;
le16 target_attribute;
le16 lcns_to_follow;
le16 record_offset;
le16 attribute_offset;
le16 cluster_index;
le16 attribute_flags;
le32 target_vcn;
le32 reserved3;
le64 lcn_list[0];
} __attribute__((__packed__));
struct {
leLSN transaction_lsn;
leLSN attributes_lsn;
leLSN names_lsn;
leLSN dirty_pages_lsn;
le64 unknown_list[0];
} __attribute__((__packed__));
} __attribute__((__packed__));
} __attribute__((__packed__)) LOG_RECORD;
struct BUFFER {
unsigned int num;
unsigned int size;
unsigned int headsz;
BOOL safe;
union {
struct RESTART_PAGE_HEADER restart;
struct RECORD_PAGE_HEADER record;
char data[1];
} block; /* variable length, keep at the end */
} ;
struct ACTION_RECORD {
struct ACTION_RECORD *next;
struct ACTION_RECORD *prev;
int num;
unsigned int flags;
struct LOG_RECORD record; /* variable length, keep at the end */
} ;
enum { /* Flag values for ACTION_RECORD */
ACTION_TO_REDO = 1 /* Committed, possibly not synced */
} ;
struct ATTR {
u64 inode;
u64 lsn;
le32 type;
u16 key;
u16 namelen;
le16 name[1];
} ;
struct BITMAP_ACTION {
le32 firstbit;
le32 count;
} ;
/* Danger in arrays : contains le64's though size is not a multiple of 8 */
typedef struct ATTR_OLD { /* Format up to Win10 (44 bytes) */
le64 unknown1;
le64 unknown2;
le64 inode;
leLSN lsn;
le32 unknown3;
le32 type;
le32 unknown4;
} __attribute__((__packed__)) ATTR_OLD;
typedef struct ATTR_NEW { /* Format since Win10 (40 bytes) */
le64 unknown1;
le64 unknown2;
le32 type;
le32 unknown3;
le64 inode;
leLSN lsn;
} __attribute__((__packed__)) ATTR_NEW;
extern u32 clustersz;
extern int clusterbits;
extern u32 blocksz;
extern int blockbits;
extern u16 bytespersect;
extern u64 mftlcn;
extern u32 mftrecsz;
extern int mftrecbits;
extern u32 mftcnt; /* number of entries */
extern BOOL optc;
extern BOOL optn;
extern int opts;
extern int optv;
extern unsigned int redocount;
extern unsigned int undocount;
extern ntfs_inode *log_ni;
extern ntfs_attr *log_na;
extern u64 logfilelcn;
extern u32 logfilesz; /* bytes */
extern u64 redos_met;
extern u64 committed_lsn;
extern u64 synced_lsn;
extern u64 latest_lsn;
extern u64 restart_lsn;
extern struct RESTART_AREA restart;
extern struct RESTART_CLIENT client;
const char *actionname(int op);
const char *mftattrname(ATTR_TYPES attr);
void showname(const char *prefix, const char *name, int cnt);
int fixnamelen(const char *name, int len);
BOOL within_lcn_range(const struct LOG_RECORD *logr);
struct ATTR *getattrentry(unsigned int key, unsigned int lth);
void copy_attribute(struct ATTR *pa, const char *buf, int length);
u32 get_undo_offset(const struct LOG_RECORD *logr);
u32 get_redo_offset(const struct LOG_RECORD *logr);
u32 get_extra_offset(const struct LOG_RECORD *logr);
BOOL exception(int num);
struct STORE;
BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp);
extern int play_undos(ntfs_volume *vol, const struct ACTION_RECORD *firstundo);
extern int play_redos(ntfs_volume *vol, const struct ACTION_RECORD *firstredo);
extern void show_redos(void);
extern void freeclusterentry(struct STORE*);
void hexdump(const char *buf, unsigned int lth);

View File

@ -5,7 +5,7 @@
* Copyright (c) 2002-2005 Anton Altaparmakov
* Copyright (c) 2002-2003 Richard Russon
* Copyright (c) 2007 Yura Pakhuchiy
* Copyright (c) 2011-2014 Jean-Pierre Andre
* Copyright (c) 2011-2015 Jean-Pierre Andre
*
* This utility will resize an NTFS volume without data loss.
*
@ -404,7 +404,7 @@ static void version(void)
printf("Copyright (c) 2002-2005 Anton Altaparmakov\n");
printf("Copyright (c) 2002-2003 Richard Russon\n");
printf("Copyright (c) 2007 Yura Pakhuchiy\n");
printf("Copyright (c) 2011-2014 Jean-Pierre Andre\n");
printf("Copyright (c) 2011-2015 Jean-Pierre Andre\n");
printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -1327,11 +1327,23 @@ static void expand_attribute_runlist(ntfs_volume *vol, struct DELAYED *delayed)
#endif
type = delayed->type;
rl = delayed->rl;
ni = ntfs_inode_open(vol,mref);
/* The MFT inode is permanently open, do not reopen or close */
if (mref == FILE_MFT)
ni = vol->mft_ni;
else
ni = ntfs_inode_open(vol,mref);
if (ni) {
na = ntfs_attr_open(ni, type,
if (mref == FILE_MFT)
na = (le32_eq(type, AT_DATA) ? vol->mft_na : vol->mftbmp_na);
else
na = ntfs_attr_open(ni, type,
delayed->attr_name, delayed->name_len);
if (na) {
/*
* The runlist is first updated in memory, and
* the updated one is used for updating on device
*/
if (!ntfs_attr_map_whole_runlist(na)) {
if (replace_runlist(na,rl,delayed->lowest_vcn)
|| ntfs_attr_update_mapping_pairs(na,0))
@ -1341,12 +1353,13 @@ static void expand_attribute_runlist(ntfs_volume *vol, struct DELAYED *delayed)
} else
perr_exit("Could not map attribute 0x%lx in inode %lld",
(long)le32_to_cpu(type),(long long)mref);
ntfs_attr_close(na);
if (mref != FILE_MFT)
ntfs_attr_close(na);
} else
perr_exit("Could not open attribute 0x%lx in inode %lld",
(long)le32_to_cpu(type),(long long)mref);
ntfs_inode_mark_dirty(ni);
if (ntfs_inode_close(ni))
if ((mref != FILE_MFT) && ntfs_inode_close(ni))
perr_exit("Failed to close inode %lld through the library",
(long long)mref);
} else
@ -1354,6 +1367,91 @@ static void expand_attribute_runlist(ntfs_volume *vol, struct DELAYED *delayed)
(long long)mref);
}
/*
* Reload the MFT before merging delayed updates of runlist
*
* The delayed updates of runlists are those which imply updating
* the runlists which overflow from their original MFT record.
* Such updates must be done in the new location of the MFT and
* the allocations must be recorded in the new location of the
* MFT bitmap.
* The MFT data and MFT bitmap may themselves have delayed parts
* of their runlists, and at this stage, their runlists may have
* been partially updated on disk, and partially to be updated.
* Their in-memory runlists still point at the old location, they
* are obsolete, and we have to read the partially updated runlist
* from the device before merging the delayed updates.
*
* Returns 0 if successful
* -1 otherwise
*/
static int reload_mft(ntfs_resize_t *resize)
{
ntfs_inode *ni;
ntfs_attr *na;
int r;
int xi;
r = 0;
/* get the base inode */
ni = resize->vol->mft_ni;
if (!ntfs_file_record_read(resize->vol, FILE_MFT, &ni->mrec, NULL)) {
for (xi=0; !r && xi<resize->vol->mft_ni->nr_extents; xi++) {
r = ntfs_file_record_read(resize->vol,
ni->extent_nis[xi]->mft_no,
&ni->extent_nis[xi]->mrec, NULL);
}
if (!r) {
/* reopen the MFT bitmap, and swap vol->mftbmp_na */
na = ntfs_attr_open(resize->vol->mft_ni,
AT_BITMAP, NULL, 0);
if (na && !ntfs_attr_map_whole_runlist(na)) {
ntfs_attr_close(resize->vol->mftbmp_na);
resize->vol->mftbmp_na = na;
} else
r = -1;
}
if (!r) {
/* reopen the MFT data, and swap vol->mft_na */
na = ntfs_attr_open(resize->vol->mft_ni,
AT_DATA, NULL, 0);
if (na && !ntfs_attr_map_whole_runlist(na)) {
ntfs_attr_close(resize->vol->mft_na);
resize->vol->mft_na = na;
} else
r = -1;
}
} else
r = -1;
return (r);
}
/*
* Re-record the MFT extents in MFT bitmap
*
* When both MFT data and MFT bitmap have delayed runlists, MFT data
* is updated first, and the extents may be recorded at old location.
*/
static int record_mft_in_bitmap(ntfs_resize_t *resize)
{
ntfs_inode *ni;
int r;
int xi;
r = 0;
/* get the base inode */
ni = resize->vol->mft_ni;
for (xi=0; !r && xi<resize->vol->mft_ni->nr_extents; xi++) {
r = ntfs_bitmap_set_run(resize->vol->mftbmp_na,
ni->extent_nis[xi]->mft_no, 1);
}
return (r);
}
/*
* Process delayed runlist updates
*/
@ -1365,9 +1463,26 @@ static void delayed_updates(ntfs_resize_t *resize)
if (ntfs_volume_get_free_space(resize->vol))
err_exit("Failed to determine free space\n");
if (resize->delayed_runlists && reload_mft(resize))
err_exit("Failed to reload the MFT for delayed updates\n");
/*
* Important : updates to MFT must come first, so that
* the new location of MFT is used for adding needed extents.
* Now, there are runlists in the MFT bitmap and MFT data.
* Extents to MFT bitmap have to be stored in the new MFT
* data, and extents to MFT data have to be recorded in
* the MFT bitmap.
* So we update MFT data first, and we record the MFT
* extents again in the MFT bitmap if they were recorded
* in the old location.
*/
while (resize->delayed_runlists) {
delayed = resize->delayed_runlists;
expand_attribute_runlist(resize->vol, delayed);
if ((delayed->mref == FILE_MFT) && le32_eq(delayed->type, AT_BITMAP))
record_mft_in_bitmap(resize);
resize->delayed_runlists = resize->delayed_runlists->next;
if (delayed->attr_name)
free(delayed->attr_name);
@ -1385,6 +1500,7 @@ static void delayed_updates(ntfs_resize_t *resize)
static void replace_later(ntfs_resize_t *resize, runlist *rl, runlist *head_rl)
{
struct DELAYED *delayed;
struct DELAYED *previous;
ATTR_RECORD *a;
MFT_REF mref;
leMFT_REF lemref;
@ -1415,8 +1531,21 @@ static void replace_later(ntfs_resize_t *resize, runlist *rl, runlist *head_rl)
delayed->lowest_vcn = sle64_to_cpu(a->lowest_vcn);
delayed->rl = rl;
delayed->head_rl = head_rl;
delayed->next = resize->delayed_runlists;
resize->delayed_runlists = delayed;
/* Queue ahead of list if this is MFT or head is not MFT */
if ((delayed->mref == FILE_MFT)
|| !resize->delayed_runlists
|| (resize->delayed_runlists->mref != FILE_MFT)) {
delayed->next = resize->delayed_runlists;
resize->delayed_runlists = delayed;
} else {
/* Queue after all MFTs is this is not MFT */
previous = resize->delayed_runlists;
while (previous->next
&& (previous->next->mref == FILE_MFT))
previous = previous->next;
delayed->next = previous->next;
previous->next = delayed;
}
} else
perr_exit("Could not store delayed update data");
}
@ -1983,10 +2112,17 @@ static int handle_mftdata(ntfs_resize_t *resize, int do_mftdata)
static void relocate_attributes(ntfs_resize_t *resize, int do_mftdata)
{
int ret;
leMFT_REF lemref;
MFT_REF base_mref;
if (!(resize->ctx = attr_get_search_ctx(NULL, resize->mrec)))
exit(1);
lemref = resize->mrec->base_mft_record;
if (!le64_cmpz(lemref))
base_mref = MREF(le64_to_cpu(lemref));
else
base_mref = resize->mref;
while (!ntfs_attrs_walk(resize->ctx)) {
if (le32_eq(resize->ctx->attr->type, AT_END))
break;
@ -2004,6 +2140,11 @@ static void relocate_attributes(ntfs_resize_t *resize, int do_mftdata)
le32_eq(resize->ctx->attr->type, AT_DATA))
continue;
/* Do not relocate bad clusters */
if ((base_mref == FILE_BadClus)
&& (le32_eq(resize->ctx->attr->type, AT_DATA)))
continue;
relocate_attribute(resize);
}
@ -2181,60 +2322,6 @@ static void advise_on_resize(ntfs_resize_t *resize)
print_advise(vol, resize->last_unsupp);
}
static void rl_expand(runlist **rl, const VCN last_vcn)
{
int len;
runlist *p = *rl;
len = rl_items(p) - 1;
if (len <= 0)
err_exit("rl_expand: bad runlist length: %d\n", len);
if (p[len].vcn > last_vcn)
err_exit("rl_expand: length is already more than requested "
"(%lld > %lld)\n",
(long long)p[len].vcn, (long long)last_vcn);
if (p[len - 1].lcn == LCN_HOLE) {
p[len - 1].length += last_vcn - p[len].vcn;
p[len].vcn = last_vcn;
} else if (p[len - 1].lcn >= 0) {
p = realloc(*rl, (++len + 1) * sizeof(runlist_element));
if (!p)
perr_exit("rl_expand: realloc");
p[len - 1].lcn = LCN_HOLE;
p[len - 1].length = last_vcn - p[len - 1].vcn;
rl_set(p + len, last_vcn, LCN_ENOENT, 0LL);
*rl = p;
} else
err_exit("rl_expand: bad LCN: %lld\n",
(long long)p[len - 1].lcn);
}
static void rl_truncate(runlist **rl, const VCN last_vcn)
{
int len;
VCN vcn;
len = rl_items(*rl) - 1;
if (len <= 0)
err_exit("rl_truncate: bad runlist length: %d\n", len);
vcn = (*rl)[len].vcn;
if (vcn < last_vcn)
rl_expand(rl, last_vcn);
else if (vcn > last_vcn)
if (ntfs_rl_truncate(rl, last_vcn) == -1)
perr_exit("ntfs_rl_truncate");
}
/**
* bitmap_file_data_fixup
*
@ -2247,6 +2334,37 @@ static void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm)
ntfs_bit_set(bm->bm, (u64)cluster, 1);
}
/*
* Open the attribute $BadClust:$Bad and get its runlist
*/
static ntfs_attr *open_badclust_bad_attr(ntfs_attr_search_ctx *ctx)
{
ntfs_inode *base_ni;
ntfs_attr *na;
static ntfschar Bad[4] = {
const_cpu_to_le16('$'), const_cpu_to_le16('B'),
const_cpu_to_le16('a'), const_cpu_to_le16('d')
} ;
base_ni = ctx->base_ntfs_ino;
if (!base_ni)
base_ni = ctx->ntfs_ino;
na = ntfs_attr_open(base_ni, AT_DATA, Bad, 4);
if (!na) {
err_printf("Could not access the bad sector list\n");
} else {
if (ntfs_attr_map_whole_runlist(na) || !na->rl) {
err_printf("Could not decode the bad sector list\n");
ntfs_attr_close(na);
ntfs_inode_close(base_ni);
na = (ntfs_attr*)NULL;
}
}
return (na);
}
/**
* truncate_badclust_bad_attr
*
@ -2257,27 +2375,26 @@ static void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm)
*/
static void truncate_badclust_bad_attr(ntfs_resize_t *resize)
{
ATTR_RECORD *a;
runlist *rl_bad;
ntfs_inode *base_ni;
ntfs_attr *na;
s64 nr_clusters = resize->new_volume_size;
ntfs_volume *vol = resize->vol;
a = resize->ctx->attr;
if (!a->non_resident)
/* FIXME: handle resident attribute value */
err_exit("Resident attribute in $BadClust isn't supported!\n");
na = open_badclust_bad_attr(resize->ctx);
if (!na) {
err_printf("Could not access the bad sector list\n");
exit(1);
}
base_ni = na->ni;
if (ntfs_attr_truncate(na,nr_clusters << vol->cluster_size_bits)) {
err_printf("Could not adjust the bad sector list\n");
exit(1);
}
na->ni->flags = le32_or(na->ni->flags, FILE_ATTR_SPARSE_FILE);
NInoFileNameSetDirty(na->ni);
if (!(rl_bad = ntfs_mapping_pairs_decompress(vol, a, NULL)))
perr_exit("ntfs_mapping_pairs_decompress");
rl_truncate(&rl_bad, nr_clusters);
a->highest_vcn = cpu_to_sle64(nr_clusters - 1LL);
a->allocated_size = cpu_to_sle64(nr_clusters * vol->cluster_size);
a->data_size = cpu_to_sle64(nr_clusters * vol->cluster_size);
if (!replace_attribute_runlist(resize, rl_bad))
free(rl_bad);
ntfs_attr_close(na);
ntfs_inode_mark_dirty(base_ni);
}
/**
@ -2439,7 +2556,7 @@ static void close_inode_and_context(ntfs_attr_search_ctx *ctx)
static int check_bad_sectors(ntfs_volume *vol)
{
ntfs_attr_search_ctx *ctx;
ntfs_inode *base_ni;
ntfs_attr *na;
runlist *rl;
s64 i, badclusters = 0;
@ -2447,27 +2564,12 @@ static int check_bad_sectors(ntfs_volume *vol)
lookup_data_attr(vol, FILE_BadClus, "$Bad", &ctx);
base_ni = ctx->base_ntfs_ino;
if (!base_ni)
base_ni = ctx->ntfs_ino;
if (NInoAttrList(base_ni)) {
err_printf("Too many bad sectors have been detected!\n");
printf("%s", many_bad_sectors_msg);
na = open_badclust_bad_attr(ctx);
if (!na) {
err_printf("Could not access the bad sector list\n");
exit(1);
}
if (!ctx->attr->non_resident)
err_exit("Resident attribute in $BadClust! Please report to "
"%s\n", NTFS_DEV_LIST);
/*
* FIXME: The below would be partial for non-base records in the
* not yet supported multi-record case. Alternatively use audited
* ntfs_attr_truncate after an umount & mount.
*/
if (!(rl = ntfs_mapping_pairs_decompress(vol, ctx->attr, NULL)))
perr_exit("Decompressing $BadClust:$Bad mapping pairs failed");
rl = na->rl;
for (i = 0; rl[i].length; i++) {
/* CHECKME: LCN_RL_NOT_MAPPED check isn't needed */
if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
@ -2493,7 +2595,7 @@ static int check_bad_sectors(ntfs_volume *vol)
"problems and massive data loss!!!\n");
}
free(rl);
ntfs_attr_close(na);
#if CLEAN_EXIT
close_inode_and_context(ctx);
#else
@ -2514,12 +2616,9 @@ static void truncate_badclust_file(ntfs_resize_t *resize)
lookup_data_attr(resize->vol, FILE_BadClus, "$Bad", &resize->ctx);
/* FIXME: sanity_check_attr(ctx->attr); */
resize->mref = FILE_BadClus;
truncate_badclust_bad_attr(resize);
if (write_mft_record(resize->vol, resize->ctx->ntfs_ino->mft_no,
resize->ctx->mrec))
perr_exit("Couldn't update $BadClust");
#if CLEAN_EXIT
close_inode_and_context(resize->ctx);
#else
@ -2539,6 +2638,7 @@ static void truncate_bitmap_file(ntfs_resize_t *resize)
printf("Updating $Bitmap file ...\n");
lookup_data_attr(resize->vol, FILE_Bitmap, NULL, &resize->ctx);
resize->mref = FILE_Bitmap;
truncate_bitmap_data_attr(resize);
if (resize->new_mft_start) {

View File

@ -26,7 +26,8 @@ is equivalent to
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-a\fR, \fB\-\-all\fR
Wipe all unused space. This may take significant time.
Wipe all unused space. This may take significant time. If the option
\-\-unused-fast (or -U) is also present, the faster wiping method is used.
.TP
\fB\-b\fR, \fB\-\-bytes\fR BYTE-LIST
Define the allowed replacement bytes which are drawn randomly to overwrite
@ -47,7 +48,7 @@ Use this option with caution.
Show a list of options with a brief description of each one.
.TP
\fB\-i\fR, \fB\-\-info\fR
Display details about unused space.
Display details about unused space, without wiping anything.
.TP
\fB\-l\fR, \fB\-\-logfile\fR
Overwrite the logfile (update journal).
@ -82,7 +83,8 @@ 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.
Display more debug/warning/error messages. This option may be used twice
to display even more messages.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license of

View File

@ -873,6 +873,9 @@ static s64 wipe_tails(ntfs_volume *vol, int byte, enum action act)
nr_mft_records = vol->mft_na->initialized_size >>
vol->mft_record_size_bits;
/* Avoid getting fixup warnings on unitialized inodes */
NVolSetNoFixupWarn(vol);
for (inode_num = FILE_first_user; inode_num < nr_mft_records;
inode_num++) {
s64 attr_wiped;
@ -881,7 +884,10 @@ static s64 wipe_tails(ntfs_volume *vol, int byte, enum action act)
ntfs_log_verbose("Inode %lld - ", (long long)inode_num);
ni = ntfs_inode_open(vol, inode_num);
if (!ni) {
ntfs_log_verbose("Could not open inode\n");
if (opts.verbose)
ntfs_log_verbose("Could not open inode\n");
else
ntfs_log_verbose("\r");
continue;
}
@ -920,6 +926,7 @@ close_inode:
ntfs_inode_close(ni);
}
close_abort :
NVolClearNoFixupWarn(vol);
ntfs_log_quiet("wipe_tails 0x%02x, %lld bytes\n", byte,
(long long)total);
return total;
@ -974,6 +981,12 @@ static s64 wipe_mft(ntfs_volume *vol, int byte, enum action act)
// We know that the end marker will only take 4 bytes
size = le32_to_cpu(rec->bytes_in_use) - 4;
if ((size <= 0) || (size > (int)vol->mft_record_size)) {
ntfs_log_error("Bad mft record %lld\n",
(long long)i);
total = -1;
goto free;
}
if (act == act_info) {
//ntfs_log_info("mft %d\n", size);
total += size;
@ -1233,6 +1246,9 @@ static s64 wipe_directory(ntfs_volume *vol, int byte, enum action act)
nr_mft_records = vol->mft_na->initialized_size >>
vol->mft_record_size_bits;
/* Avoid getting fixup warnings on unitialized inodes */
NVolSetNoFixupWarn(vol);
for (inode_num = 5; inode_num < nr_mft_records; inode_num++) {
u32 indx_record_size;
s64 wiped;
@ -1333,6 +1349,7 @@ close_inode:
ntfs_inode_close(ni);
}
NVolClearNoFixupWarn(vol);
ntfs_log_quiet("wipe_directory 0x%02x, %lld bytes\n", byte,
(long long)total);
return total;
@ -1720,14 +1737,18 @@ static int destroy_record(ntfs_volume *nv, const s64 record,
return -2;
}
/* Avoid getting fixup warnings on unitialized inodes */
NVolSetNoFixupWarn(nv);
/* Read the MFT reocrd of the i-node */
if (ntfs_attr_mst_pread(mft, nv->mft_record_size * record, 1LL,
nv->mft_record_size, file->mft) < 1) {
NVolClearNoFixupWarn(nv);
ntfs_attr_close(mft);
free_file(file);
return -3;
}
NVolClearNoFixupWarn(nv);
ntfs_attr_close(mft);
mft = NULL;
@ -2246,9 +2267,14 @@ int main(int argc, char *argv[])
break;
}
ntfs_log_info(
"%lld bytes were wiped (excluding undelete data)\n",
(long long)total);
if (opts.noaction || opts.info)
ntfs_log_info("%lld bytes would be wiped"
" (excluding undelete data)\n",
(long long)total);
else
ntfs_log_info("%lld bytes were wiped"
" (excluding undelete data)\n",
(long long)total);
}
result = 0;
umount:

4829
ntfsprogs/playlog.c 100644

File diff suppressed because it is too large Load Diff

View File

@ -1201,4 +1201,28 @@ char *ntfs_utils_reformat(char *out, int sz, const char *fmt)
return (out);
}
/*
* Translate paths to files submitted from Windows
*
* Translate Windows directory separators to Unix ones
*
* Returns the translated path, to be freed by caller
* NULL if there was an error, with errno set
*/
char *ntfs_utils_unix_path(const char *in)
{
char *out;
int i;
out = strdup(in);
if (out) {
for (i=0; in[i]; i++)
if (in[i] == '\\')
out[i] = '/';
} else
errno = ENOMEM;
return (out);
}
#endif

View File

@ -107,18 +107,19 @@ int mft_next_record(struct mft_search_ctx *ctx);
*/
#define MAX_FMT 1536
char *ntfs_utils_reformat(char *out, int sz, const char *fmt);
char *ntfs_utils_unix_path(const char *in);
#define ntfs_log_redirect(fn,fi,li,le,d,fmt, args...) \
do { char buf[MAX_FMT]; ntfs_log_redirect(fn,fi,li,le,d, \
ntfs_utils_reformat(buf,MAX_FMT,fmt), args); } while (0)
do { char _b[MAX_FMT]; ntfs_log_redirect(fn,fi,li,le,d, \
ntfs_utils_reformat(_b,MAX_FMT,fmt), args); } while (0)
#define printf(fmt, args...) \
do { char buf[MAX_FMT]; \
printf(ntfs_utils_reformat(buf,MAX_FMT,fmt), args); } while (0)
do { char _b[MAX_FMT]; \
printf(ntfs_utils_reformat(_b,MAX_FMT,fmt), args); } while (0)
#define fprintf(str, fmt, args...) \
do { char buf[MAX_FMT]; \
fprintf(str, ntfs_utils_reformat(buf,MAX_FMT,fmt), args); } while (0)
do { char _b[MAX_FMT]; \
fprintf(str, ntfs_utils_reformat(_b,MAX_FMT,fmt), args); } while (0)
#define vfprintf(file, fmt, args) \
do { char buf[MAX_FMT]; vfprintf(file, \
ntfs_utils_reformat(buf,MAX_FMT,fmt), args); } while (0)
do { char _b[MAX_FMT]; vfprintf(file, \
ntfs_utils_reformat(_b,MAX_FMT,fmt), args); } while (0)
#endif
/**

View File

@ -71,7 +71,6 @@ install-exec-local: install-rootbinPROGRAMS
$(MKDIR_P) "$(DESTDIR)/sbin"
$(LN_S) -f "$(rootbindir)/ntfs-3g" "$(DESTDIR)/sbin/mount.ntfs-3g"
$(LN_S) -f "$(rootbindir)/lowntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g"
endif
install-data-local: install-man8
$(LN_S) -f ntfs-3g.8 "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8"
@ -79,7 +78,6 @@ install-data-local: install-man8
uninstall-local:
$(RM) -f "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8"
if ENABLE_MOUNT_HELPER
$(RM) -f "$(DESTDIR)/sbin/mount.ntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g"
endif

View File

@ -124,20 +124,24 @@
#error "Incompatible options KERNELACLS and KERNELPERMS"
#endif
#if CACHEING & (KERNELACLS | !KERNELPERMS)
#warning "Fuse cacheing is only usable with basic permissions checked by kernel"
#endif
#if !CACHEING
#define ATTR_TIMEOUT 0.0
#define ENTRY_TIMEOUT 0.0
#else
#if defined(__sun) && defined (__SVR4)
#define ATTR_TIMEOUT 10.0
#define ENTRY_TIMEOUT 10.0
#else /* defined(__sun) && defined (__SVR4) */
/*
* FUSE cacheing is only usable with basic permissions
* checked by the kernel with external fuse >= 2.8
*/
#if KERNELACLS | !KERNELPERMS
#warning "Fuse cacheing is only usable with basic permissions checked by kernel"
#endif
#define ATTR_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0)
#define ENTRY_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0)
#endif /* defined(__sun) && defined (__SVR4) */
#endif
#define GHOSTLTH 40 /* max length of a ghost file name - see ghostformat */
@ -170,6 +174,7 @@ typedef struct fill_item {
typedef struct fill_context {
struct fill_item *first;
struct fill_item *last;
off_t off;
fuse_req_t req;
fuse_ino_t ino;
BOOL filled;
@ -1052,7 +1057,7 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx,
sz = fuse_add_direntry(fill_ctx->req,
&current->buf[current->off],
current->bufsize - current->off,
filename, &st, current->off);
filename, &st, current->off + fill_ctx->off);
if (!sz || ((current->off + sz) > current->bufsize)) {
newone = (ntfs_fuse_fill_item_t*)ntfs_malloc
(sizeof(ntfs_fuse_fill_item_t)
@ -1063,11 +1068,12 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx,
newone->next = (ntfs_fuse_fill_item_t*)NULL;
current->next = newone;
fill_ctx->last = newone;
fill_ctx->off += current->off;
current = newone;
sz = fuse_add_direntry(fill_ctx->req,
current->buf,
current->bufsize - current->off,
filename, &st, current->off);
filename, &st, fill_ctx->off);
if (!sz) {
errno = EIO;
ntfs_log_error("Could not add a"
@ -1124,6 +1130,7 @@ static void ntfs_fuse_opendir(fuse_req_t req, fuse_ino_t ino,
= (ntfs_fuse_fill_item_t*)NULL;
fill->filled = FALSE;
fill->ino = ino;
fill->off = 0;
}
fi->fh = (long)fill;
}
@ -1171,8 +1178,19 @@ static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
fill = (ntfs_fuse_fill_context_t*)(long)fi->fh;
if (fill && (fill->ino == ino)) {
if (fill->filled && !off) {
/* Rewinding : make sure to clear existing results */
current = fill->first;
while (current) {
current = current->next;
free(fill->first);
fill->first = current;
}
fill->filled = FALSE;
}
if (!fill->filled) {
/* initial call : build the full list */
current = (ntfs_fuse_fill_item_t*)NULL;
first = (ntfs_fuse_fill_item_t*)ntfs_malloc
(sizeof(ntfs_fuse_fill_item_t) + size);
if (first) {
@ -1182,6 +1200,7 @@ static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
fill->req = req;
fill->first = first;
fill->last = first;
fill->off = 0;
ni = ntfs_inode_open(ctx->vol,INODE(ino));
if (!ni)
err = -errno;
@ -1196,12 +1215,23 @@ static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
if (ntfs_inode_close(ni))
set_fuse_error(&err);
}
if (!err)
fuse_reply_buf(req, first->buf,
first->off);
/* reply sent, now must exit with no error */
fill->first = first->next;
free(first);
if (!err) {
off_t loc = 0;
/*
* In some circumstances, the queue gets
* reinitialized by releasedir() + opendir(),
* apparently always on end of partial buffer.
* Files may be missing or duplicated.
*/
while (first
&& ((loc < off) || !first->off)) {
loc += first->off;
fill->first = first->next;
free(first);
first = fill->first;
}
current = first;
}
} else
err = -errno;
} else {
@ -1212,6 +1242,8 @@ static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
free(fill->first);
fill->first = current;
}
}
if (!err) {
if (current) {
fuse_reply_buf(req, current->buf, current->off);
fill->first = current->next;

View File

@ -1,7 +1,7 @@
/*
* Display and audit security attributes in an NTFS volume
*
* Copyright (c) 2007-2014 Jean-Pierre Andre
* Copyright (c) 2007-2015 Jean-Pierre Andre
*
* Options :
* -a auditing security data
@ -212,6 +212,15 @@
* - decoded more "well-known" and generic SIDs
* - showed Windows ownership in verbose situations
* - fixed apparent const violations
*
* Dec 2014, version 1.4.3
* - fixed displaying "UserMapping" as a file name
*
* Mar 2015, version 1.4.5
* - adapted to new NTFS ACLs when owner is same as group
*
* May 2015, version 1.4.6
* - made to load shared library based on generic name
*/
/*
@ -235,7 +244,7 @@
* General parameters which may have to be adapted to needs
*/
#define AUDT_VERSION "1.4.2"
#define AUDT_VERSION "1.4.6"
#define GET_FILE_SECURITY "ntfs_get_file_security"
#define SET_FILE_SECURITY "ntfs_set_file_security"
@ -3737,14 +3746,14 @@ void basictest(int kind, BOOL isdir, const SID *owner, const SID *group)
24064, 28160,
24064, 28160,
24064, 28160,
25416, 29512
24904, 29000
} ;
u32 expecthash[] = {
0x8f80865b, 0x7bc7960,
0x8fd9ecfe, 0xddd4db0,
0xa8b07400, 0xa189c20,
0xc5689a00, 0xb6c09000,
0x94bfb419, 0xa4311791
0xb040e509, 0x4f4db7f7
} ;
#if POSIXACLS
struct POSIX_SECURITY *pxdesc;
@ -3886,7 +3895,8 @@ void basictest(int kind, BOOL isdir, const SID *owner, const SID *group)
(unsigned long)count,(unsigned long)acecount,
(unsigned long)acecount/count,acecount*100L/count%100L);
if (acecount != expectcnt[kind]) {
printf("** Error : expected ACE count %lu\n",
printf("** Error : ACE count %lu instead of %lu\n",
(unsigned long)acecount,
(unsigned long)expectcnt[kind]);
errors++;
}
@ -3900,7 +3910,8 @@ void basictest(int kind, BOOL isdir, const SID *owner, const SID *group)
(unsigned long)pxcount,(unsigned long)pxacecount,
(unsigned long)pxacecount/pxcount,pxacecount*100L/pxcount%100L);
if (pxacecount != expectcnt[kind]) {
printf("** Error : expected ACE count %lu\n",
printf("** Error : ACE count %lu instead of %lu\n",
(unsigned long)pxacecount,
(unsigned long)expectcnt[kind]);
errors++;
}
@ -4844,9 +4855,9 @@ BOOL proposal(const char *name, const char *attr)
printf("# and gid of the Linux owner and group of ");
printname(stdout,name);
printf(", then\n");
printf("# insert the modified lines into .NTFS-3G/Usermapping, with .NTFS-3G\n");
printf("# insert the modified lines into .NTFS-3G/UserMapping, with .NTFS-3G\n");
} else
printf("# Insert the above lines into .NTFS-3G/Usermapping, with .NTFS-3G\n");
printf("# Insert the above lines into .NTFS-3G/UserMapping, with .NTFS-3G\n");
#ifdef WIN32
printf("# being a directory of the root of the NTFS file system.\n");
@ -7282,9 +7293,15 @@ void dumpalloc(const char *txt)
if (firstalloc) {
printf("alloc table at %s\n",txt);
for (q=firstalloc; q; q=q->next)
#ifdef __x86_64__
printf("%08llx : %u bytes at %08llx allocated at %s line %d\n",
(long long)q,(unsigned int)q->size,
(long long)q->alloc,q->file,q->line);
#else
printf("%08lx : %u bytes at %08lx allocated at %s line %d\n",
(long)q,(unsigned int)q->size,
(long)q->alloc,q->file,q->line);
#endif
}
}
@ -7374,7 +7391,13 @@ BOOL chkisalloc(void *p, const char *file, int line)
} else
q = (struct CHKALLOC*)NULL;
if (!p || !q) {
printf("error in %s %d : 0x%lx not allocated\n",file,line,(long)p);
#ifdef __x86_64__
printf("error in %s %d : 0x%llx not allocated\n",file,line,
(long long)p);
#else
printf("error in %s %d : 0x%lx not allocated\n",file,line,
(long)p);
#endif
}
return (p && q);
}

View File

@ -56,8 +56,13 @@
#else
#define USESTUBS 0 /* direct calls to API, based on following definitions */
#define ENVNTFS3G "NTFS3G"
#define LIBFILE64 "/lib64/libntfs-3g.so.4921"
#define LIBFILE "/lib/libntfs-3g.so.4921"
#if defined(__SVR4)
#define LIBFILE64 "/usr/lib/amd64/libntfs-3g.so"
#define LIBFILE "/usr/lib/libntfs-3g.so"
#else
#define LIBFILE64 "/lib64/libntfs-3g.so"
#define LIBFILE "/lib/libntfs-3g.so"
#endif
#endif
#define MAPDIR ".NTFS-3G"