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.cedge.strict_endians
commit
34bb449324
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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);
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
¤t->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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue