Merge remote branch 'linux-ntfs/libntfs-3g_port-v2_0_0' into PERMISSION_HANDLING_BRANCH

Conflicts:
	.cvsignore
	AUTHORS
	CREDITS
	ChangeLog
	NEWS
	README
	TODO.libntfs
	autogen.sh
	configure.ac
	include/ntfs/Makefile.am
	libntfs-3g/misc.c
	libntfs/Makefile.am
	libntfs/gnome-vfs-method.c
	libntfs/gnome-vfs-module.c
	ntfsprogs.spec.in
	ntfsprogs/.cvsignore
	ntfsprogs/mkntfs.c
	ntfsprogs/ntfscat.8.in
	ntfsprogs/ntfsclone.c
	ntfsprogs/ntfscp.8.in
	ntfsprogs/ntfsinfo.c
	ntfsprogs/ntfsprogs.8.in
	ntfsprogs/ntfsresize.c
	ntfsprogs/ntfsrm.c
	ntfsprogs/ntfsundelete.h
	ntfsprogs/upcase.c
	ntfsprogs/utils.c
	test/Makefile.am
This commit is contained in:
Erik Larsson 2010-12-17 09:04:01 +01:00
commit bcdc76f12d
47 changed files with 5900 additions and 2958 deletions

View File

@ -65,7 +65,6 @@ Thanks,
**********
- add ability to copy multiply files at once.
- add ability to create new files.
***********
@ -93,7 +92,6 @@ Thanks,
* ntfsmount *
*************
- Cache opened inodes for faster access.
**************

View File

@ -278,7 +278,7 @@ fi
compile_crypto=false
if test "$enable_crypto" != "no"; then
have_libgcrypt=false
AM_PATH_LIBGCRYPT(1.2.0, [ have_libgcrypt=true ],
AM_PATH_LIBGCRYPT(1.2.2, [ have_libgcrypt=true ],
[
if test "$enable_crypto" = "yes"; then
AC_MSG_ERROR([ntfsprogs crypto code requires the gcrypt library.])
@ -287,17 +287,29 @@ if test "$enable_crypto" != "no"; then
fi
])
have_libgnutls=false
PKG_CHECK_MODULES(GNUTLS_MODULE, gnutls >= 1.2.8, [ have_libgnutls=true ],
[
PKG_CHECK_MODULES(GNUTLS, gnutls >= 1.4.4, [ have_libgnutls=true ],
if test "$enable_crypto" = "yes"; then
AC_MSG_ERROR([ntfsprogs crypto code requires the gnutls library.])
else
AC_MSG_WARN([ntfsprogs crypto code requires the gnutls library.])
fi
])
)
have_libconfig=false
PKG_CHECK_MODULES(libconfig, libconfig >= 1.0.1, [ have_libconfig=true ],
if test "$enable_crypto" = "yes"; then
AC_MSG_ERROR([ntfsprogs crypto code requires the libconfig.])
else
AC_MSG_WARN([ntfsprogs crypto code requires the libconfig.])
fi
)
if test "$have_libgcrypt" = "true"; then
if test "$have_libgnutls" = "true"; then
if test "$have_libconfig" = "true"; then
compile_crypto=true
AC_DEFINE([ENABLE_CRYPTO], 1,
[Define this to 1 if you want to enable support of
encrypted files in libntfs and utilities.])
fi
fi
fi
fi
@ -309,6 +321,42 @@ all_includes="$all_includes $USER_INCLUDES"
AC_SUBST(all_includes)
AC_SUBST(all_libraries)
# Specify support for generating DCE compliant UUIDs (aka GUIDs). We check if
# uuid/uuid.h header is present and the uuid library is present that goes with
# it and then check if uuid_generate() is present and usable.
#
# DCE UUIDs are enabled by default and can be disabled with the --disable-uuid
# option to the configure script.
AC_ARG_WITH(uuid, [
--with-uuid@<:@=PFX@:>@ generate DCE compliant UUIDs, with optional prefix
to uuid library and headers @<:@default=detect@:>@
--without-uuid do not generate DCE compliant UUIDs],
if test "$with_uuid" = "yes"; then
extrapath=default
elif test "$with_uuid" = "no"; then
extrapath=
else
extrapath=$with_uuid
fi,
extrapath=default
)
if test "x$extrapath" != "x"; then
if test "x$extrapath" != "xdefault"; then
MKNTFS_CPPFLAGS="$MKNTFS_CPPFLAGS -I$extrapath/include"
MKNTFS_LIBS="$MKNTFS_LIBS -L$extrapath/lib"
fi
AC_CHECK_HEADER([uuid/uuid.h],
AC_CHECK_LIB([uuid], [uuid_generate],
AC_DEFINE([ENABLE_UUID], 1,
[Define this to 1 if you want to enable generation of
DCE compliant UUIDs.])
MKNTFS_LIBS="$MKNTFS_LIBS -luuid",
AC_MSG_WARN([ntfsprogs DCE compliant UUID generation code requires the uuid library.]),
),
AC_MSG_WARN([ntfsprogs DCE compliant UUID generation code requires the uuid library.]),
)
fi
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
@ -317,7 +365,7 @@ AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
endian.h byteswap.h sys/byteorder.h sys/endian.h sys/param.h \
sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h sys/vfs.h \
sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h linux/hdreg.h \
machine/endian.h gcrypt.h windows.h gnutls/pkcs12.h syslog.h])
machine/endian.h windows.h syslog.h pwd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL

46
include/ntfs/crypto.h Normal file
View File

@ -0,0 +1,46 @@
/**
* crypto.h - Exports for dealing with encrypted files. Part of the
* Linux-NTFS project.
*
* Copyright (c) 2007 Yura Pakhuchiy
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_CRYPTO_H
#define _NTFS_CRYPTO_H
extern ntfschar NTFS_EFS[5];
/*
* This is our Big Secret (TM) structure, so do not allow anyone even read it
* values. ;-) In fact, it is private because exist only in libntfs version
* compiled with cryptography support, so users can not depend on it.
*/
typedef struct _ntfs_crypto_attr ntfs_crypto_attr;
/*
* These functions should not be used directly. They are called for encrypted
* attributes from corresponding functions without _crypto_ part.
*/
extern int ntfs_crypto_attr_open(ntfs_attr *na);
extern void ntfs_crypto_attr_close(ntfs_attr *na);
extern s64 ntfs_crypto_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
void *b);
#endif /* _NTFS_CRYPTO_H */

10
libntfs/config Normal file
View File

@ -0,0 +1,10 @@
# libntfs sample configuration file
crypto : {
keys = (
("/home/yura/ntfs/my3.pfx", "my3"), # key with password
# ("/home/yura/ntfs/my-rec.pfx", ""), // password-less key
("/home/yura/ntfs/my.pfx") /* password-less key */
);
};

1518
libntfs/crypto.c Normal file

File diff suppressed because it is too large Load Diff

546
libntfs/freebsd_io.c Normal file
View File

@ -0,0 +1,546 @@
/**
* freebsd_io.c - FreeBSD disk io functions. Part of the Linux-NTFS project.
*
* FreeBSD 5.0+ does not have block devices and requires read/writes from/to
* character devices to be sector aligned.
*
* Copyright (c) 2006 Max Khon
* Copyright (c) 2006 Anton Altaparmakov
* Copyright (c) 2006 Yura Pakhuchiy
*
* 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
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file 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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_LINUX_FD_H
#include <linux/fd.h>
#endif
#include <sys/disk.h>
#include "types.h"
#include "mst.h"
#include "debug.h"
#include "device.h"
#include "logging.h"
typedef struct {
int fd;
s64 pos;
s32 block_size;
s64 media_size;
} freebsd_fd;
#define DEV_FD(dev) (((freebsd_fd *) dev->d_private))
#define RAW_IO_ALIGNED(dev, offset, count) \
(DEV_FD(dev)->block_size == 0 || \
((offset) % DEV_FD(dev)->block_size == 0 && \
(count) % DEV_FD(dev)->block_size == 0))
#define RAW_IO_ALIGN(dev, offset) \
((offset) / DEV_FD(dev)->block_size * DEV_FD(dev)->block_size)
#define RAW_IO_MAX_SIZE (128 * 1024 * 1024)
/* Define to nothing if not present on this system. */
#ifndef O_EXCL
# define O_EXCL 0
#endif
/**
* Get block_size and media_size
*/
static int freebsd_get_size(struct ntfs_device *dev)
{
off_t ms;
int bs;
struct stat sb;
if (fstat(DEV_FD(dev)->fd, &sb) < 0) {
ntfs_log_perror("Failed to stat '%s'", dev->d_name);
return -1;
}
if (S_ISREG(sb.st_mode)) {
DEV_FD(dev)->media_size = sb.st_size;
ntfs_log_trace("%s: regular file (media_size %lld)\n",
dev->d_name, DEV_FD(dev)->media_size);
return 0;
}
if (ioctl(DEV_FD(dev)->fd, DIOCGSECTORSIZE, &bs) < 0) {
ntfs_log_perror("Failed to ioctl(DIOCGSECTORSIZE) '%s'",
dev->d_name);
return -1;
}
DEV_FD(dev)->block_size = bs;
ntfs_log_trace("%s: block size %d\n", dev->d_name, bs);
if (ioctl(DEV_FD(dev)->fd, DIOCGMEDIASIZE, &ms) < 0) {
ntfs_log_perror("Failed to ioctl(DIOCGMEDIASIZE) '%s'",
dev->d_name);
return -1;
}
DEV_FD(dev)->media_size = ms;
ntfs_log_trace("%s: media size %lld\n", dev->d_name, ms);
return 0;
}
/**
* freebsd_pread - Aligned read
*/
static inline ssize_t freebsd_pread(struct ntfs_device *dev, char *buf,
size_t count, s64 offset)
{
return pread(DEV_FD(dev)->fd, buf, count, offset);
}
/**
* freebsd_pwrite - Aligned write
*/
static inline ssize_t freebsd_pwrite(struct ntfs_device *dev, const char *buf,
size_t count, s64 offset)
{
return pwrite(DEV_FD(dev)->fd, buf, count, offset);
}
/**
* ntfs_device_freebsd_io_open - Open a device and lock it exclusively
* @dev:
* @flags:
*
* Description...
*
* Returns:
*/
static int ntfs_device_freebsd_io_open(struct ntfs_device *dev, int flags)
{
#if 0
struct flock flk;
#endif
struct stat sbuf;
int err;
if (NDevOpen(dev)) {
errno = EBUSY;
return -1;
}
if (stat(dev->d_name, &sbuf)) {
ntfs_log_perror("Failed to access '%s'", dev->d_name);
return -1;
}
if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
NDevSetBlock(dev);
dev->d_private = malloc(sizeof(freebsd_fd));
if (!dev->d_private)
return -1;
DEV_FD(dev)->fd = -1;
DEV_FD(dev)->pos = 0;
DEV_FD(dev)->block_size = 0;
DEV_FD(dev)->media_size = 0;
DEV_FD(dev)->fd = open(dev->d_name, flags);
if (DEV_FD(dev)->fd == -1) {
err = errno;
goto err_out;
}
if ((flags & O_RDWR) != O_RDWR)
NDevSetReadOnly(dev);
#if 0
memset(&flk, 0, sizeof(flk));
if (NDevReadOnly(dev))
flk.l_type = F_RDLCK;
else
flk.l_type = F_WRLCK;
flk.l_whence = SEEK_SET;
flk.l_start = flk.l_len = 0LL;
if (fcntl(DEV_FD(dev)->fd, F_SETLK, &flk)) {
err = errno;
ntfs_log_perror("Failed to %s lock '%s'", NDevReadOnly(dev) ?
"read" : "write", dev->d_name);
if (close(DEV_FD(dev)->fd))
ntfs_log_perror("Failed to close '%s'", dev->d_name);
goto err_out;
}
#endif
if (freebsd_get_size(dev) < 0) {
err = errno;
close(DEV_FD(dev)->fd);
goto err_out;
}
NDevSetOpen(dev);
return 0;
err_out:
free(dev->d_private);
dev->d_private = NULL;
errno = err;
return -1;
}
/**
* ntfs_device_freebsd_io_close - Close the device, releasing the lock
* @dev:
*
* Description...
*
* Returns:
*/
static int ntfs_device_freebsd_io_close(struct ntfs_device *dev)
{
#if 0
struct flock flk;
#endif
if (!NDevOpen(dev)) {
errno = EBADF;
return -1;
}
if (NDevDirty(dev))
fsync(DEV_FD(dev)->fd);
#if 0
/* Release exclusive (mandatory) lock on the whole device. */
memset(&flk, 0, sizeof(flk));
flk.l_type = F_UNLCK;
flk.l_whence = SEEK_SET;
flk.l_start = flk.l_len = 0LL;
if (fcntl(DEV_FD(dev)->fd, F_SETLK, &flk))
ntfs_log_perror("ntfs_device_freebsd_io_close: Warning: Could not "
"unlock %s", dev->d_name);
#endif
/* Close the file descriptor and clear our open flag. */
if (close(DEV_FD(dev)->fd))
return -1;
NDevClearOpen(dev);
free(dev->d_private);
dev->d_private = NULL;
return 0;
}
/**
* ntfs_device_freebsd_io_seek - Seek to a place on the device
* @dev:
* @offset:
* @whence:
*
* Description...
*
* Returns:
*/
static s64 ntfs_device_freebsd_io_seek(struct ntfs_device *dev, s64 offset,
int whence)
{
s64 abs_pos;
ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence);
switch (whence) {
case SEEK_SET:
abs_pos = offset;
break;
case SEEK_CUR:
abs_pos = DEV_FD(dev)->pos + offset;
break;
case SEEK_END:
abs_pos = DEV_FD(dev)->media_size + offset;
break;
default:
ntfs_log_trace("Wrong mode %d.\n", whence);
errno = EINVAL;
return -1;
}
if (abs_pos < 0 || abs_pos > DEV_FD(dev)->media_size) {
ntfs_log_trace("Seeking outsize seekable area.\n");
errno = EINVAL;
return -1;
}
DEV_FD(dev)->pos = abs_pos;
return abs_pos;
}
/**
* ntfs_device_freebsd_io_read - Read from the device, from the current location
* @dev:
* @buf:
* @count:
*
* Description...
*
* Returns:
*/
static s64 ntfs_device_freebsd_io_read(struct ntfs_device *dev, void *buf,
s64 count)
{
s64 start, start_aligned;
s64 end, end_aligned;
size_t count_aligned;
char *buf_aligned;
ssize_t nr;
/* short-circuit for regular files */
start = DEV_FD(dev)->pos;
if (count > RAW_IO_MAX_SIZE)
count = RAW_IO_MAX_SIZE;
if (RAW_IO_ALIGNED(dev, start, count)) {
nr = freebsd_pread(dev, buf, count, start);
if (nr <= 0)
return nr;
DEV_FD(dev)->pos += nr;
return nr;
}
/*
* +- start_aligned +- end_aligned
* | |
* | +- start +- end |
* v v v v
* |----------|----------|----------|
* ^ ^
* +----- count ------+
* ^ ^
* +-------- count_aligned ---------+
*/
start_aligned = RAW_IO_ALIGN(dev, start);
end = start + count;
end_aligned = RAW_IO_ALIGN(dev, end) +
(RAW_IO_ALIGNED(dev, end, 0) ? 0 : DEV_FD(dev)->block_size);
count_aligned = end_aligned - start_aligned;
ntfs_log_trace(
"%s: count = 0x%llx/0x%x, start = 0x%llx/0x%llx, end = 0x%llx/0x%llx\n",
dev->d_name, count, count_aligned,
start, start_aligned, end, end_aligned);
/* allocate buffer */
buf_aligned = malloc(count_aligned);
if (buf_aligned == NULL) {
ntfs_log_trace("malloc(%d) failed\n", count_aligned);
return -1;
}
/* read aligned data */
nr = freebsd_pread(dev, buf_aligned, count_aligned, start_aligned);
if (nr == 0)
return 0;
if (nr < 0 || nr < start - start_aligned) {
free(buf_aligned);
return -1;
}
/* copy out */
memcpy(buf, buf_aligned + (start - start_aligned), count);
free(buf_aligned);
nr -= start - start_aligned;
if (nr > count)
nr = count;
DEV_FD(dev)->pos += nr;
return nr;
}
/**
* ntfs_device_freebsd_io_write - Write to the device, at the current location
* @dev:
* @buf:
* @count:
*
* Description...
*
* Returns:
*/
static s64 ntfs_device_freebsd_io_write(struct ntfs_device *dev, const void *buf,
s64 count)
{
s64 start, start_aligned;
s64 end, end_aligned;
size_t count_aligned;
char *buf_aligned;
ssize_t nw;
if (NDevReadOnly(dev)) {
errno = EROFS;
return -1;
}
NDevSetDirty(dev);
/* short-circuit for regular files */
start = DEV_FD(dev)->pos;
if (count > RAW_IO_MAX_SIZE)
count = RAW_IO_MAX_SIZE;
if (RAW_IO_ALIGNED(dev, start, count)) {
nw = freebsd_pwrite(dev, buf, count, start);
if (nw <= 0)
return nw;
DEV_FD(dev)->pos += nw;
return nw;
}
/*
* +- start_aligned +- end_aligned
* | |
* | +- start +- end |
* v v v v
* |----------|----------|----------|
* ^ ^
* +----- count ------+
* ^ ^
* +-------- count_aligned ---------+
*/
start_aligned = RAW_IO_ALIGN(dev, start);
end = start + count;
end_aligned = RAW_IO_ALIGN(dev, end) +
(RAW_IO_ALIGNED(dev, end, 0) ? 0 : DEV_FD(dev)->block_size);
count_aligned = end_aligned - start_aligned;
ntfs_log_trace(
"%s: count = 0x%llx/0x%x, start = 0x%llx/0x%llx, end = 0x%llx/0x%llx\n",
dev->d_name, count, count_aligned,
start, start_aligned, end, end_aligned);
/* allocate buffer */
buf_aligned = malloc(count_aligned);
if (buf_aligned == NULL) {
ntfs_log_trace("malloc(%d) failed\n", count_aligned);
return -1;
}
/* read aligned lead-in */
if (freebsd_pread(dev, buf_aligned, DEV_FD(dev)->block_size, start_aligned) != DEV_FD(dev)->block_size) {
ntfs_log_trace("read lead-in failed\n");
free(buf_aligned);
return -1;
}
/* read aligned lead-out */
if (end != end_aligned && count_aligned > DEV_FD(dev)->block_size) {
if (freebsd_pread(dev, buf_aligned + count_aligned - DEV_FD(dev)->block_size, DEV_FD(dev)->block_size, end_aligned - DEV_FD(dev)->block_size) != DEV_FD(dev)->block_size) {
ntfs_log_trace("read lead-out failed\n");
free(buf_aligned);
return -1;
}
}
/* copy data to write */
memcpy(buf_aligned + (start - start_aligned), buf, count);
/* write aligned data */
nw = freebsd_pwrite(dev, buf_aligned, count_aligned, start_aligned);
free(buf_aligned);
if (nw < 0 || nw < start - start_aligned)
return -1;
nw -= start - start_aligned;
if (nw > count)
nw = count;
DEV_FD(dev)->pos += nw;
return nw;
}
/**
* ntfs_device_freebsd_io_sync - Flush any buffered changes to the device
* @dev:
*
* Description...
*
* Returns:
*/
static int ntfs_device_freebsd_io_sync(struct ntfs_device *dev)
{
if (!NDevReadOnly(dev)) {
int res = fsync(DEV_FD(dev)->fd);
if (!res)
NDevClearDirty(dev);
return res;
}
return 0;
}
/**
* ntfs_device_freebsd_io_stat - Get information about the device
* @dev:
* @buf:
*
* Description...
*
* Returns:
*/
static int ntfs_device_freebsd_io_stat(struct ntfs_device *dev, struct stat *buf)
{
return fstat(DEV_FD(dev)->fd, buf);
}
/**
* ntfs_device_freebsd_io_ioctl - Perform an ioctl on the device
* @dev:
* @request:
* @argp:
*
* Description...
*
* Returns:
*/
static int ntfs_device_freebsd_io_ioctl(struct ntfs_device *dev, int request,
void *argp)
{
return ioctl(DEV_FD(dev)->fd, request, argp);
}
/**
* Device operations for working with unix style devices and files.
*/
struct ntfs_device_operations ntfs_device_unix_io_ops = {
.open = ntfs_device_freebsd_io_open,
.close = ntfs_device_freebsd_io_close,
.seek = ntfs_device_freebsd_io_seek,
.read = ntfs_device_freebsd_io_read,
.write = ntfs_device_freebsd_io_write,
.sync = ntfs_device_freebsd_io_sync,
.stat = ntfs_device_freebsd_io_stat,
.ioctl = ntfs_device_freebsd_io_ioctl,
};

34
libntfs/libntfs.8.in Normal file
View File

@ -0,0 +1,34 @@
.\" Copyright (c) 2007 Yura Pakhuchiy
.\" This file may be copied under the terms of the GNU Public License.
.TH LIBNTFS 8 "September 2007" "ntfsprogs @VERSION@"
.SH NAME
libntfs \- library for accessing and managing NTFS volumes
.SH OVERVIEW
\fBlibntfs\fR is GPL licensed library for accessing and managing NTFS volumes.
It is used by\fB ntfsprogs\fR and some other projects.
.SH ACCESSING ENCRYPTED FILES
Programs that uses\fB libntfs\fR can transparently access encrypted files on
NTFS volumes if\fB libntfs\fR was compiled with \fB--enable-crypto\fR option
(it depends on\fB libgcrypt\fR,\fB GNU TLS\fR and \fBlibconfig\fR) and user
wrote configuration file. Configuration file should be placed in
\fB/etc/libntfs/config\fR or \fB$(HOME)/.libntfs/config\fR and contain list
of .PFX key files (see ntfsprogs-<version>/libntfs/config in ntfsprogs source
tarball for sample configuration file). Key files can be created/exported
using\fB cipher\fR tool under windows.
.SH AUTHORS
\fBlibntfs\fR was written by Anton Altaparmakov, Richard Russon, Szabolcs Szakacsits, Yuval Fledel and Yura Pakhuchiy.
.SH AVAILABILITY
The \fBntfsprogs\fR can be downloaded from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
These manual pages can be viewed online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR ntfsprogs (8),
.BR libntfs\-gnomevfs (8)

63
libntfs/misc.c Normal file
View File

@ -0,0 +1,63 @@
/**
* misc.c - Miscellaneous functions. Part of the Linux-NTFS project.
*
* Copyright (c) 2006 Szabolcs Szakacsits
*
* 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
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "support.h"
#include "logging.h"
/**
* ntfs_calloc - A logging supported calloc(3)
*
* Return a pointer to the allocated memory or NULL if the request fails.
* Memory is initialized with zeros.
*/
void *ntfs_calloc(size_t size)
{
void *p;
p = calloc(1, size);
if (!p)
ntfs_log_perror("Failed to calloc %lld bytes", (long long)size);
return p;
}
/**
* ntfs_malloc - A logging supported malloc(3)
*
* Return a pointer to the allocated memory or NULL if the request fails.
* Memory is uninitialized.
*/
void *ntfs_malloc(size_t size)
{
void *p;
p = malloc(size);
if (!p)
ntfs_log_perror("Failed to malloc %lld bytes", (long long)size);
return p;
}

View File

@ -17,7 +17,7 @@ bin_PROGRAMS = ntfsfix ntfsinfo ntfscluster ntfsls ntfscat ntfscmp
sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize ntfsclone \
ntfscp
EXTRA_PROGRAMS = ntfsdump_logfile ntfswipe ntfstruncate ntfsmove \
ntfsmftalloc
ntfsmftalloc ntfsck
man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8 \
ntfsundelete.8 ntfsresize.8 ntfsprogs.8 ntfsls.8 \
@ -40,8 +40,9 @@ ntfsfix_SOURCES = ntfsfix.c utils.c utils.h
ntfsfix_LDADD = $(AM_LIBS)
ntfsfix_LDFLAGS = $(AM_LFLAGS)
mkntfs_SOURCES = attrdef.c attrdef.h upcase.c upcase.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h
mkntfs_LDADD = $(AM_LIBS)
mkntfs_CPPFLAGS = $(AM_CPPFLAGS) $(MKNTFS_CPPFLAGS)
mkntfs_SOURCES = attrdef.c attrdef.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h
mkntfs_LDADD = $(AM_LIBS) $(MKNTFS_LIBS)
mkntfs_LDFLAGS = $(AM_LFLAGS)
ntfslabel_SOURCES = ntfslabel.c utils.c utils.h
@ -80,6 +81,10 @@ ntfscp_SOURCES = ntfscp.c utils.c utils.h
ntfscp_LDADD = $(AM_LIBS)
ntfscp_LDFLAGS = $(AM_LFLAGS)
ntfsck_SOURCES = ntfsck.c utils.c utils.h
ntfsck_LDADD = $(AM_LIBS)
ntfsck_LDFLAGS = $(AM_LFLAGS)
ntfscmp_SOURCES = ntfscmp.c utils.c utils.h
ntfscmp_LDADD = $(AM_LIBS)
ntfscmp_LDFLAGS = $(AM_LFLAGS)
@ -108,8 +113,9 @@ ntfsdump_logfile_LDFLAGS= $(AM_LFLAGS)
if ENABLE_CRYPTO
ntfsdecrypt_SOURCES = ntfsdecrypt.c utils.c utils.h
ntfsdecrypt_LDADD = $(AM_LIBS)
ntfsdecrypt_LDFLAGS = $(AM_LFLAGS) -lgcrypt -lgnutls
ntfsdecrypt_LDADD = $(AM_LIBS) $(GNUTLS_LIBS) $(LIBGCRYPT_LIBS)
ntfsdecrypt_LDFLAGS = $(AM_LFLAGS)
ntfsdecrypt_CFLAGS = $(GNUTLS_CFLAGS) $(LIBGCRYPT_CFLAGS)
endif
# Extra targets

View File

@ -1,158 +1,4 @@
/**
* attrdef_ntfs12_array
*/
const unsigned char attrdef_ntfs12_array[2400] = {
36, 0, 83, 0, 84, 0, 65, 0, 78, 0, 68, 0, 65, 0, 82, 0,
68, 0, 95, 0, 73, 0, 78, 0, 70, 0, 79, 0, 82, 0, 77, 0,
65, 0, 84, 0, 73, 0, 79, 0, 78, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
48, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0,
36, 0, 65, 0, 84, 0, 84, 0, 82, 0, 73, 0, 66, 0, 85, 0,
84, 0, 69, 0, 95, 0, 76, 0, 73, 0, 83, 0, 84, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 70, 0, 73, 0, 76, 0, 69, 0, 95, 0, 78, 0, 65, 0,
77, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0,
68, 0, 0, 0, 0, 0, 0, 0, 66, 2, 0, 0, 0, 0, 0, 0,
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
86, 0, 69, 0, 82, 0, 83, 0, 73, 0, 79, 0, 78, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
36, 0, 83, 0, 69, 0, 67, 0, 85, 0, 82, 0, 73, 0, 84, 0,
89, 0, 95, 0, 68, 0, 69, 0, 83, 0, 67, 0, 82, 0, 73, 0,
80, 0, 84, 0, 79, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
78, 0, 65, 0, 77, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
73, 0, 78, 0, 70, 0, 79, 0, 82, 0, 77, 0, 65, 0, 84, 0,
73, 0, 79, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
36, 0, 68, 0, 65, 0, 84, 0, 65, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 73, 0, 78, 0, 68, 0, 69, 0, 88, 0, 95, 0, 82, 0,
79, 0, 79, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 73, 0, 78, 0, 68, 0, 69, 0, 88, 0, 95, 0, 65, 0,
76, 0, 76, 0, 79, 0, 67, 0, 65, 0, 84, 0, 73, 0, 79, 0,
78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 66, 0, 73, 0, 84, 0, 77, 0, 65, 0, 80, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 83, 0, 89, 0, 77, 0, 66, 0, 79, 0, 76, 0, 73, 0,
67, 0, 95, 0, 76, 0, 73, 0, 78, 0, 75, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 69, 0, 65, 0, 95, 0, 73, 0, 78, 0, 70, 0, 79, 0,
82, 0, 77, 0, 65, 0, 84, 0, 73, 0, 79, 0, 78, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
36, 0, 69, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#include "attrdef.h"
/**
* attrdef_ntfs3x_array

View File

@ -1,7 +1,6 @@
#ifndef _NTFS_ATTRDEF_H_
#define _NTFS_ATTRDEF_H_
extern const unsigned char attrdef_ntfs12_array[2400];
extern const unsigned char attrdef_ntfs3x_array[2560];
#endif /* _NTFS_ATTRDEF_H_ */

View File

@ -1,222 +1,268 @@
/**
* boot_array - the first 3429 bytes of $Boot
* The first 3429 bytes of $Boot. The rest is just zero. Total 8192 bytes.
*/
const unsigned char boot_array[3429] = {
235, 91, 144, 78, 84, 70, 83, 32, 32, 32, 32, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 51, 192,
142, 208, 188, 0, 124, 251, 184, 192, 7, 142, 216, 199, 6, 84, 0, 0,
0, 199, 6, 86, 0, 0, 0, 199, 6, 91, 0, 16, 0, 184, 0, 13,
142, 192, 43, 219, 232, 7, 0, 104, 0, 13, 104, 102, 2, 203, 80, 83,
81, 82, 6, 102, 161, 84, 0, 102, 3, 6, 28, 0, 102, 51, 210, 102,
15, 183, 14, 24, 0, 102, 247, 241, 254, 194, 136, 22, 90, 0, 102, 139,
208, 102, 193, 234, 16, 247, 54, 26, 0, 136, 22, 37, 0, 163, 88, 0,
161, 24, 0, 42, 6, 90, 0, 64, 59, 6, 91, 0, 118, 3, 161, 91,
0, 80, 180, 2, 139, 22, 88, 0, 177, 6, 210, 230, 10, 54, 90, 0,
139, 202, 134, 233, 138, 54, 37, 0, 178, 128, 205, 19, 88, 114, 42, 1,
6, 84, 0, 131, 22, 86, 0, 0, 41, 6, 91, 0, 118, 11, 193, 224,
5, 140, 194, 3, 208, 142, 194, 235, 138, 7, 90, 89, 91, 88, 195, 190,
89, 1, 235, 8, 190, 227, 1, 235, 3, 190, 57, 1, 232, 9, 0, 190,
173, 1, 232, 3, 0, 251, 235, 254, 172, 60, 0, 116, 9, 180, 14, 187,
7, 0, 205, 16, 235, 242, 195, 29, 0, 65, 32, 100, 105, 115, 107, 32,
114, 101, 97, 100, 32, 101, 114, 114, 111, 114, 32, 111, 99, 99, 117, 114,
114, 101, 100, 46, 13, 10, 0, 41, 0, 65, 32, 107, 101, 114, 110, 101,
108, 32, 102, 105, 108, 101, 32, 105, 115, 32, 109, 105, 115, 115, 105, 110,
103, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 100, 105, 115, 107, 46,
13, 10, 0, 37, 0, 65, 32, 107, 101, 114, 110, 101, 108, 32, 102, 105,
108, 101, 32, 105, 115, 32, 116, 111, 111, 32, 100, 105, 115, 99, 111, 110,
116, 105, 103, 117, 111, 117, 115, 46, 13, 10, 0, 51, 0, 73, 110, 115,
101, 114, 116, 32, 97, 32, 115, 121, 115, 116, 101, 109, 32, 100, 105, 115,
107, 101, 116, 116, 101, 32, 97, 110, 100, 32, 114, 101, 115, 116, 97, 114,
116, 13, 10, 116, 104, 101, 32, 115, 121, 115, 116, 101, 109, 46, 13, 10,
0, 23, 0, 92, 78, 84, 76, 68, 82, 32, 105, 115, 32, 99, 111, 109,
112, 114, 101, 115, 115, 101, 100, 46, 13, 10, 0, 0, 0, 0, 85, 170,
5, 0, 78, 0, 84, 0, 76, 0, 68, 0, 82, 0, 4, 0, 36, 0,
73, 0, 51, 0, 48, 0, 0, 224, 0, 0, 0, 48, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 140, 200, 142, 216, 193, 224, 4, 250, 139, 224,
251, 102, 15, 183, 6, 11, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227,
102, 163, 78, 2, 102, 139, 14, 64, 0, 128, 249, 0, 15, 143, 14, 0,
246, 217, 102, 184, 1, 0, 0, 0, 102, 211, 224, 235, 8, 144, 102, 161,
78, 2, 102, 247, 225, 102, 163, 82, 2, 102, 15, 183, 30, 11, 0, 102,
51, 210, 102, 247, 243, 102, 163, 86, 2, 232, 44, 4, 102, 139, 14, 74,
2, 102, 137, 14, 34, 2, 102, 3, 14, 82, 2, 102, 137, 14, 38, 2,
102, 3, 14, 82, 2, 102, 137, 14, 42, 2, 102, 3, 14, 82, 2, 102,
137, 14, 58, 2, 102, 3, 14, 82, 2, 102, 137, 14, 66, 2, 102, 184,
144, 0, 0, 0, 102, 139, 14, 34, 2, 232, 65, 9, 102, 11, 192, 15,
132, 22, 254, 102, 163, 46, 2, 102, 184, 160, 0, 0, 0, 102, 139, 14,
38, 2, 232, 40, 9, 102, 163, 50, 2, 102, 184, 176, 0, 0, 0, 102,
139, 14, 42, 2, 232, 22, 9, 102, 163, 54, 2, 102, 161, 46, 2, 102,
11, 192, 15, 132, 227, 253, 103, 128, 120, 8, 0, 15, 133, 218, 253, 103,
102, 141, 80, 16, 103, 3, 66, 4, 103, 102, 15, 182, 72, 12, 102, 137,
14, 94, 2, 103, 102, 139, 72, 8, 102, 137, 14, 90, 2, 102, 161, 90,
2, 102, 15, 183, 14, 11, 0, 102, 51, 210, 102, 247, 241, 102, 163, 98,
2, 102, 161, 66, 2, 102, 3, 6, 90, 2, 102, 163, 70, 2, 102, 131,
62, 50, 2, 0, 15, 132, 25, 0, 102, 131, 62, 54, 2, 0, 15, 132,
135, 253, 102, 139, 30, 54, 2, 30, 7, 102, 139, 62, 70, 2, 232, 177,
1, 102, 15, 183, 14, 0, 2, 102, 184, 2, 2, 0, 0, 232, 153, 6,
102, 11, 192, 15, 132, 88, 253, 103, 102, 139, 0, 30, 7, 102, 139, 62,
58, 2, 232, 209, 4, 102, 161, 58, 2, 102, 187, 128, 0, 0, 0, 102,
185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 203, 0, 102, 11,
192, 15, 132, 42, 253, 103, 102, 15, 183, 88, 12, 102, 129, 227, 255, 0,
0, 0, 15, 133, 30, 253, 102, 139, 216, 104, 0, 32, 7, 102, 43, 255,
232, 79, 1, 138, 22, 36, 0, 184, 232, 3, 142, 192, 141, 54, 11, 0,
43, 192, 104, 0, 32, 80, 203, 80, 83, 81, 82, 6, 255, 54, 91, 0,
255, 54, 84, 0, 255, 54, 86, 0, 139, 195, 193, 232, 4, 140, 193, 3,
193, 37, 255, 15, 45, 0, 16, 247, 216, 139, 14, 91, 0, 193, 225, 5,
81, 59, 193, 118, 2, 139, 193, 80, 193, 232, 5, 163, 91, 0, 232, 61,
252, 88, 89, 43, 200, 118, 11, 140, 194, 3, 208, 142, 194, 184, 0, 16,
235, 222, 143, 6, 86, 0, 143, 6, 84, 0, 143, 6, 91, 0, 7, 90,
89, 91, 88, 195, 6, 30, 102, 96, 102, 139, 218, 102, 15, 182, 14, 13,
0, 102, 247, 225, 102, 163, 84, 0, 102, 139, 195, 102, 247, 225, 163, 91,
0, 139, 223, 131, 227, 15, 140, 192, 102, 193, 239, 4, 3, 199, 80, 7,
232, 116, 255, 102, 97, 144, 31, 7, 195, 103, 3, 64, 20, 103, 102, 131,
56, 255, 15, 132, 76, 0, 103, 102, 57, 24, 15, 133, 51, 0, 102, 11,
201, 15, 133, 10, 0, 103, 128, 120, 9, 0, 15, 133, 35, 0, 195, 103,
58, 72, 9, 15, 133, 26, 0, 102, 139, 240, 103, 3, 112, 10, 232, 61,
5, 102, 81, 30, 7, 102, 139, 250, 243, 167, 102, 89, 15, 133, 1, 0,
195, 103, 102, 131, 120, 4, 0, 15, 132, 7, 0, 103, 102, 3, 64, 4,
235, 171, 102, 43, 192, 195, 102, 139, 243, 232, 18, 5, 103, 102, 3, 0,
103, 247, 64, 12, 2, 0, 15, 133, 52, 0, 103, 102, 141, 80, 16, 103,
58, 74, 64, 15, 133, 24, 0, 103, 102, 141, 114, 66, 232, 239, 4, 102,
81, 30, 7, 102, 139, 251, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103,
131, 120, 8, 0, 15, 132, 6, 0, 103, 3, 64, 8, 235, 194, 102, 51,
192, 195, 103, 128, 123, 8, 0, 15, 133, 28, 0, 6, 30, 102, 96, 103,
102, 141, 83, 16, 103, 102, 139, 10, 102, 139, 243, 103, 3, 114, 4, 243,
164, 102, 97, 144, 31, 7, 195, 103, 102, 141, 83, 16, 103, 102, 139, 74,
8, 102, 65, 102, 43, 192, 232, 1, 0, 195, 6, 30, 102, 96, 103, 128,
123, 8, 1, 15, 132, 3, 0, 233, 127, 251, 102, 131, 249, 0, 15, 133,
6, 0, 102, 97, 144, 31, 7, 195, 102, 83, 102, 80, 102, 81, 102, 87,
6, 232, 87, 3, 102, 139, 209, 7, 102, 95, 102, 89, 102, 59, 202, 15,
141, 3, 0, 102, 139, 209, 232, 171, 254, 102, 43, 202, 102, 139, 218, 102,
139, 194, 102, 15, 182, 22, 13, 0, 102, 247, 226, 102, 15, 183, 22, 11,
0, 102, 247, 226, 102, 3, 248, 102, 88, 102, 3, 195, 102, 91, 235, 170,
6, 30, 102, 96, 103, 128, 123, 8, 1, 15, 132, 3, 0, 233, 25, 251,
102, 131, 249, 0, 15, 133, 6, 0, 102, 97, 144, 31, 7, 195, 102, 83,
102, 80, 102, 81, 102, 87, 6, 102, 81, 102, 51, 210, 102, 15, 182, 14,
13, 0, 102, 247, 241, 102, 82, 232, 225, 2, 102, 15, 182, 30, 13, 0,
102, 247, 227, 102, 90, 102, 3, 194, 102, 80, 102, 15, 182, 6, 13, 0,
102, 247, 225, 102, 139, 208, 102, 88, 102, 89, 7, 102, 95, 102, 89, 102,
59, 202, 15, 141, 3, 0, 102, 139, 209, 102, 163, 84, 0, 137, 22, 91,
0, 6, 30, 102, 96, 139, 223, 131, 227, 15, 140, 192, 102, 193, 239, 4,
3, 199, 80, 7, 232, 160, 253, 102, 97, 144, 31, 7, 102, 43, 202, 102,
139, 218, 102, 139, 194, 102, 15, 183, 22, 11, 0, 102, 247, 226, 102, 3,
248, 102, 88, 102, 3, 195, 102, 91, 233, 101, 255, 6, 30, 102, 96, 38,
103, 102, 15, 183, 95, 4, 38, 103, 102, 15, 183, 79, 6, 102, 11, 201,
15, 132, 101, 250, 102, 3, 223, 102, 131, 195, 2, 102, 129, 199, 254, 1,
0, 0, 102, 73, 102, 11, 201, 15, 132, 23, 0, 38, 103, 139, 3, 38,
103, 137, 7, 102, 131, 195, 2, 102, 129, 199, 0, 2, 0, 0, 102, 73,
235, 226, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 184, 1, 0,
0, 0, 102, 163, 30, 2, 102, 161, 26, 2, 102, 3, 6, 82, 2, 102,
163, 74, 2, 102, 161, 48, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227,
102, 163, 84, 0, 102, 161, 86, 2, 163, 91, 0, 102, 139, 30, 26, 2,
30, 7, 232, 242, 252, 102, 15, 183, 251, 232, 111, 255, 102, 161, 26, 2,
102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0,
0, 0, 232, 100, 253, 102, 11, 192, 15, 132, 87, 0, 102, 139, 216, 30,
7, 102, 139, 62, 22, 2, 232, 249, 253, 102, 139, 30, 22, 2, 103, 102,
129, 59, 128, 0, 0, 0, 15, 132, 6, 0, 103, 3, 91, 4, 235, 238,
103, 102, 129, 59, 128, 0, 0, 0, 15, 133, 39, 0, 102, 83, 103, 102,
139, 67, 16, 102, 139, 62, 74, 2, 30, 7, 232, 9, 1, 102, 91, 102,
161, 82, 2, 102, 1, 6, 74, 2, 102, 255, 6, 30, 2, 103, 3, 91,
4, 235, 205, 102, 97, 144, 31, 7, 195, 102, 139, 208, 102, 139, 14, 30,
2, 102, 161, 26, 2, 102, 82, 102, 80, 102, 81, 102, 82, 102, 187, 128,
0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232,
215, 252, 102, 11, 192, 15, 132, 64, 249, 102, 139, 216, 102, 88, 232, 42,
1, 102, 11, 192, 15, 132, 7, 0, 102, 91, 102, 91, 102, 91, 195, 102,
89, 102, 88, 102, 90, 102, 3, 6, 82, 2, 226, 185, 102, 51, 192, 195,
6, 30, 102, 96, 102, 80, 102, 81, 102, 51, 210, 102, 15, 182, 30, 13,
0, 102, 247, 243, 102, 82, 232, 144, 255, 102, 11, 192, 15, 132, 249, 248,
102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 90, 102, 3, 194, 102, 163,
84, 0, 102, 89, 102, 15, 182, 30, 13, 0, 102, 59, 203, 15, 142, 19,
0, 137, 30, 91, 0, 102, 43, 203, 102, 88, 102, 3, 195, 102, 80, 102,
81, 235, 20, 144, 102, 88, 102, 3, 193, 102, 80, 137, 14, 91, 0, 102,
185, 0, 0, 0, 0, 102, 81, 6, 102, 87, 139, 223, 131, 227, 15, 140,
192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 155, 251, 102, 95, 7, 102,
3, 62, 78, 2, 102, 89, 102, 88, 102, 131, 249, 0, 15, 143, 116, 255,
102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 247, 38, 86, 2, 102,
139, 14, 86, 2, 232, 89, 255, 232, 241, 253, 102, 97, 144, 31, 7, 195,
6, 30, 102, 96, 102, 247, 38, 98, 2, 102, 139, 30, 50, 2, 102, 139,
14, 98, 2, 30, 7, 102, 139, 62, 66, 2, 232, 35, 253, 232, 203, 253,
102, 97, 144, 31, 7, 195, 102, 80, 102, 83, 102, 81, 102, 139, 30, 70,
2, 102, 139, 200, 102, 193, 232, 3, 102, 131, 225, 7, 102, 3, 216, 102,
184, 1, 0, 0, 0, 102, 211, 224, 103, 132, 3, 15, 132, 4, 0, 248,
235, 2, 144, 249, 102, 89, 102, 91, 102, 88, 195, 103, 128, 123, 8, 1,
15, 132, 4, 0, 102, 43, 192, 195, 103, 102, 141, 115, 16, 103, 102, 139,
86, 8, 102, 59, 194, 15, 135, 11, 0, 103, 102, 139, 22, 102, 59, 194,
15, 131, 4, 0, 102, 43, 192, 195, 103, 3, 94, 16, 102, 43, 246, 103,
128, 59, 0, 15, 132, 62, 0, 232, 129, 0, 102, 3, 241, 232, 57, 0,
102, 3, 202, 102, 59, 193, 15, 140, 33, 0, 102, 139, 209, 102, 80, 103,
102, 15, 182, 11, 102, 139, 193, 102, 131, 224, 15, 102, 193, 233, 4, 102,
3, 217, 102, 3, 216, 102, 67, 102, 88, 235, 196, 102, 43, 200, 102, 43,
194, 102, 3, 198, 195, 102, 43, 192, 195, 102, 43, 201, 103, 138, 11, 128,
225, 15, 102, 131, 249, 0, 15, 133, 4, 0, 102, 43, 201, 195, 102, 83,
102, 82, 102, 3, 217, 103, 102, 15, 190, 19, 102, 73, 102, 75, 102, 131,
249, 0, 15, 132, 13, 0, 102, 193, 226, 8, 103, 138, 19, 102, 75, 102,
73, 235, 235, 102, 139, 202, 102, 90, 102, 91, 195, 102, 83, 102, 82, 102,
43, 210, 103, 138, 19, 102, 131, 226, 15, 102, 43, 201, 103, 138, 11, 192,
233, 4, 102, 131, 249, 0, 15, 133, 8, 0, 102, 43, 201, 102, 90, 102,
91, 195, 102, 3, 218, 102, 3, 217, 103, 102, 15, 190, 19, 102, 73, 102,
75, 102, 131, 249, 0, 15, 132, 13, 0, 102, 193, 226, 8, 103, 138, 19,
102, 75, 102, 73, 235, 235, 102, 139, 202, 102, 90, 102, 91, 195, 102, 11,
201, 15, 133, 1, 0, 195, 102, 81, 102, 86, 103, 131, 62, 97, 15, 140,
12, 0, 103, 131, 62, 122, 15, 143, 4, 0, 103, 131, 46, 32, 102, 131,
198, 2, 226, 230, 102, 94, 102, 89, 195, 102, 80, 102, 81, 102, 139, 208,
102, 161, 46, 2, 103, 102, 141, 88, 16, 103, 3, 67, 4, 103, 102, 141,
64, 16, 102, 139, 218, 232, 158, 250, 102, 11, 192, 15, 132, 5, 0, 102,
89, 102, 89, 195, 102, 161, 50, 2, 102, 11, 192, 15, 133, 8, 0, 102,
89, 102, 89, 102, 51, 192, 195, 102, 139, 22, 50, 2, 103, 102, 141, 82,
16, 103, 102, 139, 66, 8, 102, 64, 102, 139, 30, 78, 2, 102, 247, 227,
102, 51, 210, 102, 247, 54, 90, 2, 102, 80, 102, 88, 102, 11, 192, 15,
132, 48, 0, 102, 72, 102, 80, 232, 28, 254, 114, 238, 232, 241, 253, 102,
90, 102, 89, 102, 91, 102, 83, 102, 81, 102, 82, 102, 161, 66, 2, 103,
102, 141, 64, 24, 232, 47, 250, 102, 11, 192, 116, 206, 102, 89, 102, 89,
102, 89, 195, 102, 89, 102, 89, 102, 51, 192, 195, 6, 30, 102, 96, 102,
139, 54, 66, 2, 102, 185, 32, 0, 0, 0, 102, 247, 193, 3, 0, 0,
0, 15, 133, 3, 0, 232, 13, 0, 102, 173, 232, 105, 0, 226, 235, 102,
97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 51, 192, 102, 51, 219, 176,
13, 180, 14, 187, 7, 0, 205, 16, 176, 10, 180, 14, 187, 7, 0, 205,
16, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 11, 201, 15, 133,
9, 0, 232, 208, 255, 102, 97, 144, 31, 7, 195, 102, 51, 192, 102, 51,
219, 173, 180, 14, 187, 7, 0, 205, 16, 226, 240, 232, 183, 255, 102, 97,
144, 31, 7, 195, 96, 172, 60, 0, 116, 9, 180, 14, 187, 7, 0, 205,
16, 235, 242, 97, 144, 195, 6, 30, 102, 96, 102, 185, 8, 0, 0, 0,
102, 139, 208, 102, 131, 226, 15, 102, 82, 102, 193, 232, 4, 226, 241, 102,
185, 8, 0, 0, 0, 102, 88, 102, 131, 248, 9, 15, 143, 7, 0, 102,
131, 192, 48, 235, 9, 144, 102, 131, 232, 10, 102, 131, 192, 65, 102, 51,
219, 180, 14, 187, 7, 0, 205, 16, 226, 219, 176, 32, 180, 14, 187, 7,
0, 205, 16, 102, 97, 144, 31, 7, 232, 96, 0, 195, 6, 30, 102, 96,
102, 190, 22, 13, 0, 0, 232, 79, 245, 102, 97, 144, 31, 7, 195, 6,
30, 102, 96, 102, 190, 38, 13, 0, 0, 232, 60, 245, 102, 97, 144, 31,
7, 195, 6, 30, 102, 96, 102, 190, 54, 13, 0, 0, 232, 41, 245, 102,
97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 190, 70, 13, 0, 0, 232,
22, 245, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 190, 86, 13,
0, 0, 232, 3, 245, 102, 97, 144, 31, 7, 195, 102, 80, 102, 184, 0,
0, 245, 255, 102, 64, 102, 11, 192, 117, 249, 102, 88, 195, 102, 81, 102,
80, 102, 184, 5, 0, 0, 0, 30, 7, 102, 139, 249, 232, 71, 252, 102,
139, 193, 102, 91, 102, 83, 102, 15, 183, 14, 12, 2, 102, 186, 14, 2,
0, 0, 232, 68, 248, 102, 91, 102, 89, 102, 11, 192, 15, 133, 47, 0,
102, 139, 193, 102, 139, 203, 102, 80, 102, 83, 232, 35, 0, 102, 91, 102,
95, 102, 11, 192, 15, 132, 23, 0, 30, 7, 232, 9, 252, 102, 139, 199,
102, 15, 183, 14, 12, 2, 102, 186, 14, 2, 0, 0, 232, 10, 248, 195,
102, 81, 102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186,
0, 0, 0, 0, 232, 242, 247, 102, 11, 192, 15, 132, 82, 0, 102, 139,
216, 30, 7, 102, 139, 62, 22, 2, 232, 135, 248, 30, 7, 102, 139, 30,
22, 2, 102, 89, 38, 102, 57, 15, 15, 132, 46, 0, 38, 102, 131, 63,
255, 15, 132, 45, 0, 38, 131, 127, 4, 0, 15, 132, 36, 0, 38, 102,
15, 183, 71, 4, 3, 216, 139, 195, 37, 0, 128, 116, 215, 140, 192, 5,
0, 8, 142, 192, 129, 227, 255, 127, 235, 202, 38, 102, 139, 71, 16, 195,
102, 89, 102, 51, 192, 195, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 48, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 49, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 50, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 51, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 52, 13, 10
};
#include "boot.h"
/**
* boot_array - the first 4136 bytes of $Boot
*
* The first 4136 bytes of $Boot. The rest is just zero. Total 8192 bytes.
*/
const unsigned char boot_array[4136] = {
235, 82, 144, 78, 84, 70, 83, 32, 32, 32, 32, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 250, 51, 192, 142, 208, 188, 0, 124, 251, 104, 192, 7,
31, 30, 104, 102, 0, 203, 136, 22, 14, 0, 102, 129, 62, 3, 0, 78,
84, 70, 83, 117, 21, 180, 65, 187, 170, 85, 205, 19, 114, 12, 129, 251,
85, 170, 117, 6, 247, 193, 1, 0, 117, 3, 233, 210, 0, 30, 131, 236,
24, 104, 26, 0, 180, 72, 138, 22, 14, 0, 139, 244, 22, 31, 205, 19,
159, 131, 196, 24, 158, 88, 31, 114, 225, 59, 6, 11, 0, 117, 219, 163,
15, 0, 193, 46, 15, 0, 4, 30, 90, 51, 219, 185, 0, 32, 43, 200,
102, 255, 6, 17, 0, 3, 22, 15, 0, 142, 194, 255, 6, 22, 0, 232,
64, 0, 43, 200, 119, 239, 184, 0, 187, 205, 26, 102, 35, 192, 117, 45,
102, 129, 251, 84, 67, 80, 65, 117, 36, 129, 249, 2, 1, 114, 30, 22,
104, 7, 187, 22, 104, 112, 14, 22, 104, 9, 0, 102, 83, 102, 83, 102,
85, 22, 22, 22, 104, 184, 1, 102, 97, 14, 7, 205, 26, 233, 106, 1,
144, 144, 102, 96, 30, 6, 102, 161, 17, 0, 102, 3, 6, 28, 0, 30,
102, 104, 0, 0, 0, 0, 102, 80, 6, 83, 104, 1, 0, 104, 16, 0,
180, 66, 138, 22, 14, 0, 22, 31, 139, 244, 205, 19, 102, 89, 91, 90,
102, 89, 102, 89, 31, 15, 130, 22, 0, 102, 255, 6, 17, 0, 3, 22,
15, 0, 142, 194, 255, 14, 22, 0, 117, 188, 7, 31, 102, 97, 195, 160,
248, 1, 232, 8, 0, 160, 251, 1, 232, 2, 0, 235, 254, 180, 1, 139,
240, 172, 60, 0, 116, 9, 180, 14, 187, 7, 0, 205, 16, 235, 242, 195,
13, 10, 65, 32, 100, 105, 115, 107, 32, 114, 101, 97, 100, 32, 101, 114,
114, 111, 114, 32, 111, 99, 99, 117, 114, 114, 101, 100, 0, 13, 10, 66,
79, 79, 84, 77, 71, 82, 32, 105, 115, 32, 109, 105, 115, 115, 105, 110,
103, 0, 13, 10, 66, 79, 79, 84, 77, 71, 82, 32, 105, 115, 32, 99,
111, 109, 112, 114, 101, 115, 115, 101, 100, 0, 13, 10, 80, 114, 101, 115,
115, 32, 67, 116, 114, 108, 43, 65, 108, 116, 43, 68, 101, 108, 32, 116,
111, 32, 114, 101, 115, 116, 97, 114, 116, 13, 10, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 128, 157, 178, 202, 0, 0, 85, 170,
7, 0, 66, 0, 79, 0, 79, 0, 84, 0, 77, 0, 71, 0, 82, 0,
4, 0, 36, 0, 73, 0, 51, 0, 48, 0, 0, 224, 0, 0, 0, 48,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 235, 34, 144, 144, 5, 0, 78, 0, 84, 0,
76, 0, 68, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 15, 183, 6, 11, 0,
102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 163, 82, 2, 102, 139, 14,
64, 0, 128, 249, 0, 15, 143, 14, 0, 246, 217, 102, 184, 1, 0, 0,
0, 102, 211, 224, 235, 8, 144, 102, 161, 82, 2, 102, 247, 225, 102, 163,
102, 2, 102, 15, 183, 30, 11, 0, 102, 51, 210, 102, 247, 243, 102, 163,
86, 2, 232, 149, 4, 102, 139, 14, 78, 2, 102, 137, 14, 38, 2, 102,
3, 14, 102, 2, 102, 137, 14, 42, 2, 102, 3, 14, 102, 2, 102, 137,
14, 46, 2, 102, 3, 14, 102, 2, 102, 137, 14, 62, 2, 102, 3, 14,
102, 2, 102, 137, 14, 70, 2, 102, 184, 144, 0, 0, 0, 102, 139, 14,
38, 2, 232, 131, 9, 102, 11, 192, 15, 132, 83, 254, 102, 163, 50, 2,
102, 184, 160, 0, 0, 0, 102, 139, 14, 42, 2, 232, 106, 9, 102, 163,
54, 2, 102, 184, 176, 0, 0, 0, 102, 139, 14, 46, 2, 232, 88, 9,
102, 163, 58, 2, 102, 161, 50, 2, 102, 11, 192, 15, 132, 32, 254, 103,
128, 120, 8, 0, 15, 133, 23, 254, 103, 102, 141, 80, 16, 103, 3, 66,
4, 103, 102, 15, 182, 72, 12, 102, 137, 14, 114, 2, 103, 102, 139, 72,
8, 102, 137, 14, 110, 2, 102, 161, 110, 2, 102, 15, 183, 14, 11, 0,
102, 51, 210, 102, 247, 241, 102, 163, 118, 2, 102, 161, 70, 2, 102, 3,
6, 110, 2, 102, 163, 74, 2, 102, 131, 62, 54, 2, 0, 15, 132, 29,
0, 102, 131, 62, 58, 2, 0, 15, 132, 196, 253, 102, 139, 30, 58, 2,
30, 7, 102, 139, 62, 74, 2, 102, 161, 46, 2, 232, 224, 1, 102, 15,
183, 14, 0, 2, 102, 184, 2, 2, 0, 0, 232, 34, 8, 102, 11, 192,
15, 133, 22, 0, 102, 15, 183, 14, 90, 2, 102, 184, 92, 2, 0, 0,
232, 12, 8, 102, 11, 192, 15, 132, 66, 12, 103, 102, 139, 0, 30, 7,
102, 139, 62, 62, 2, 232, 63, 6, 102, 161, 62, 2, 102, 187, 32, 0,
0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 228,
0, 102, 133, 192, 15, 133, 35, 0, 102, 161, 62, 2, 102, 187, 128, 0,
0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 196,
0, 102, 11, 192, 15, 133, 68, 0, 233, 241, 11, 102, 51, 210, 102, 185,
128, 0, 0, 0, 102, 161, 62, 2, 232, 202, 8, 102, 11, 192, 15, 132,
218, 11, 30, 7, 102, 139, 62, 62, 2, 232, 219, 5, 102, 161, 62, 2,
102, 187, 128, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0,
0, 0, 232, 128, 0, 102, 11, 192, 15, 132, 176, 11, 103, 102, 15, 183,
88, 12, 102, 129, 227, 255, 0, 0, 0, 15, 133, 165, 11, 102, 139, 216,
104, 0, 32, 7, 102, 43, 255, 102, 161, 62, 2, 232, 0, 1, 104, 0,
32, 7, 102, 43, 255, 102, 161, 62, 2, 232, 172, 10, 138, 22, 14, 0,
184, 232, 3, 142, 192, 141, 54, 11, 0, 43, 192, 104, 0, 32, 80, 203,
6, 30, 102, 96, 102, 139, 218, 102, 15, 182, 14, 13, 0, 102, 247, 225,
102, 163, 17, 0, 102, 139, 195, 102, 247, 225, 163, 22, 0, 139, 223, 131,
227, 15, 140, 192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 51, 252, 102,
97, 144, 31, 7, 195, 103, 3, 64, 20, 103, 102, 131, 56, 255, 15, 132,
76, 0, 103, 102, 57, 24, 15, 133, 51, 0, 102, 11, 201, 15, 133, 10,
0, 103, 128, 120, 9, 0, 15, 133, 35, 0, 195, 103, 58, 72, 9, 15,
133, 26, 0, 102, 139, 240, 103, 3, 112, 10, 232, 151, 6, 102, 81, 30,
7, 102, 139, 250, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103, 102, 131,
120, 4, 0, 15, 132, 7, 0, 103, 102, 3, 64, 4, 235, 171, 102, 43,
192, 195, 102, 139, 243, 232, 108, 6, 103, 102, 3, 0, 103, 247, 64, 12,
2, 0, 15, 133, 52, 0, 103, 102, 141, 80, 16, 103, 58, 74, 64, 15,
133, 24, 0, 103, 102, 141, 114, 66, 232, 73, 6, 102, 81, 30, 7, 102,
139, 251, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103, 131, 120, 8, 0,
15, 132, 6, 0, 103, 3, 64, 8, 235, 194, 102, 51, 192, 195, 103, 128,
123, 8, 0, 15, 133, 28, 0, 6, 30, 102, 96, 103, 102, 141, 83, 16,
103, 102, 139, 10, 102, 139, 243, 103, 3, 114, 4, 243, 164, 102, 97, 144,
31, 7, 195, 102, 80, 103, 102, 141, 83, 16, 102, 133, 192, 15, 133, 10,
0, 103, 102, 139, 74, 8, 102, 65, 235, 17, 144, 103, 102, 139, 66, 24,
102, 51, 210, 102, 247, 54, 82, 2, 102, 139, 200, 102, 43, 192, 102, 94,
232, 1, 0, 195, 6, 30, 102, 96, 103, 128, 123, 8, 1, 15, 132, 3,
0, 233, 107, 251, 102, 131, 249, 0, 15, 133, 6, 0, 102, 97, 144, 31,
7, 195, 102, 83, 102, 80, 102, 81, 102, 86, 102, 87, 6, 232, 145, 4,
102, 139, 209, 7, 102, 95, 102, 94, 102, 89, 102, 133, 192, 15, 132, 52,
0, 102, 59, 202, 15, 141, 3, 0, 102, 139, 209, 232, 130, 254, 102, 43,
202, 102, 139, 218, 102, 139, 194, 102, 15, 182, 22, 13, 0, 102, 247, 226,
102, 15, 183, 22, 11, 0, 102, 247, 226, 102, 3, 248, 102, 88, 102, 3,
195, 102, 91, 235, 159, 102, 133, 246, 15, 132, 3, 251, 102, 81, 102, 87,
6, 103, 102, 15, 182, 67, 9, 102, 133, 192, 15, 132, 32, 0, 102, 209,
224, 102, 43, 224, 102, 139, 252, 102, 84, 102, 86, 103, 102, 15, 183, 115,
10, 102, 3, 243, 102, 139, 200, 243, 164, 102, 94, 235, 3, 144, 102, 80,
102, 80, 103, 102, 139, 3, 102, 80, 103, 102, 139, 67, 24, 102, 80, 103,
102, 139, 86, 32, 102, 133, 210, 15, 132, 11, 0, 102, 139, 254, 30, 7,
102, 139, 194, 232, 113, 3, 102, 139, 198, 102, 90, 102, 89, 102, 66, 102,
81, 102, 86, 232, 63, 6, 102, 133, 192, 15, 132, 146, 250, 102, 94, 102,
89, 102, 139, 254, 30, 7, 232, 78, 3, 102, 139, 198, 102, 139, 217, 102,
89, 102, 90, 102, 81, 102, 86, 102, 209, 233, 232, 248, 253, 102, 133, 192,
15, 132, 107, 250, 102, 94, 102, 89, 102, 3, 225, 7, 102, 95, 102, 89,
102, 139, 208, 102, 88, 102, 91, 102, 139, 218, 233, 245, 254, 6, 30, 102,
96, 38, 103, 102, 15, 183, 95, 4, 38, 103, 102, 15, 183, 79, 6, 102,
11, 201, 15, 132, 57, 250, 102, 3, 223, 102, 131, 195, 2, 102, 129, 199,
254, 1, 0, 0, 102, 73, 102, 11, 201, 15, 132, 23, 0, 38, 103, 139,
3, 38, 103, 137, 7, 102, 131, 195, 2, 102, 129, 199, 0, 2, 0, 0,
102, 73, 235, 226, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 184,
1, 0, 0, 0, 102, 163, 34, 2, 102, 161, 30, 2, 102, 3, 6, 102,
2, 102, 163, 106, 2, 102, 3, 6, 102, 2, 102, 163, 78, 2, 102, 161,
48, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 139, 30, 78, 2,
102, 137, 7, 102, 163, 17, 0, 131, 195, 4, 102, 161, 86, 2, 102, 137,
7, 163, 22, 0, 131, 195, 4, 102, 137, 30, 78, 2, 102, 139, 30, 30,
2, 30, 7, 232, 92, 249, 102, 139, 251, 232, 81, 255, 102, 161, 30, 2,
102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0,
0, 0, 232, 16, 253, 102, 11, 192, 15, 132, 25, 1, 102, 139, 216, 30,
7, 102, 139, 62, 26, 2, 102, 51, 192, 232, 162, 253, 102, 139, 30, 26,
2, 102, 129, 63, 128, 0, 0, 0, 15, 132, 235, 0, 3, 95, 4, 235,
240, 102, 83, 102, 139, 71, 16, 102, 247, 38, 86, 2, 102, 80, 102, 51,
210, 102, 15, 182, 30, 13, 0, 102, 247, 243, 102, 82, 232, 220, 0, 102,
11, 192, 15, 132, 57, 249, 102, 139, 14, 86, 2, 102, 15, 182, 30, 13,
0, 102, 247, 227, 102, 90, 102, 3, 194, 102, 139, 30, 78, 2, 102, 137,
7, 131, 195, 4, 102, 15, 182, 6, 13, 0, 102, 43, 194, 102, 59, 193,
15, 134, 3, 0, 102, 139, 193, 102, 137, 7, 102, 43, 200, 102, 90, 15,
132, 117, 0, 102, 3, 194, 102, 80, 102, 51, 210, 102, 15, 182, 30, 13,
0, 102, 247, 243, 102, 81, 232, 130, 0, 102, 89, 102, 11, 192, 15, 132,
221, 248, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 139, 30, 78, 2,
102, 139, 23, 131, 195, 4, 102, 3, 23, 102, 59, 208, 15, 133, 21, 0,
102, 15, 182, 6, 13, 0, 102, 59, 193, 15, 134, 3, 0, 102, 139, 193,
102, 1, 7, 235, 165, 131, 195, 4, 102, 137, 30, 78, 2, 102, 137, 7,
131, 195, 4, 102, 15, 182, 6, 13, 0, 102, 59, 193, 15, 134, 3, 0,
102, 139, 193, 102, 137, 7, 235, 130, 131, 195, 4, 102, 255, 6, 34, 2,
102, 137, 30, 78, 2, 102, 91, 3, 95, 4, 102, 129, 63, 128, 0, 0,
0, 15, 132, 12, 255, 102, 97, 144, 31, 7, 195, 102, 139, 208, 102, 139,
14, 34, 2, 102, 139, 54, 106, 2, 102, 3, 54, 102, 2, 102, 82, 102,
81, 102, 82, 102, 139, 30, 106, 2, 102, 139, 62, 86, 2, 102, 139, 4,
102, 163, 17, 0, 131, 198, 4, 102, 139, 4, 163, 22, 0, 131, 198, 4,
30, 7, 232, 221, 247, 102, 43, 248, 15, 132, 8, 0, 247, 38, 11, 0,
3, 216, 235, 217, 102, 139, 62, 106, 2, 30, 7, 232, 191, 253, 102, 161,
106, 2, 102, 187, 128, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 139,
209, 232, 129, 251, 102, 11, 192, 15, 132, 244, 247, 102, 139, 216, 102, 88,
102, 86, 232, 44, 1, 102, 94, 102, 11, 192, 15, 132, 5, 0, 102, 91,
102, 91, 195, 102, 89, 102, 90, 226, 132, 102, 51, 192, 195, 6, 30, 102,
96, 102, 80, 102, 81, 102, 51, 210, 102, 15, 182, 30, 13, 0, 102, 247,
243, 102, 82, 102, 87, 232, 83, 255, 102, 95, 102, 11, 192, 15, 132, 174,
247, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 90, 102, 3, 194, 102,
163, 17, 0, 102, 89, 102, 15, 182, 30, 13, 0, 102, 59, 203, 15, 142,
19, 0, 137, 30, 22, 0, 102, 43, 203, 102, 88, 102, 3, 195, 102, 80,
102, 81, 235, 20, 144, 102, 88, 102, 3, 193, 102, 80, 137, 14, 22, 0,
102, 185, 0, 0, 0, 0, 102, 81, 6, 102, 87, 139, 223, 131, 227, 15,
140, 192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 5, 247, 102, 95, 7,
102, 3, 62, 82, 2, 102, 89, 102, 88, 102, 131, 249, 0, 15, 143, 112,
255, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 247, 38, 86, 2,
102, 139, 14, 86, 2, 232, 85, 255, 232, 210, 252, 102, 97, 144, 31, 7,
195, 6, 30, 102, 96, 102, 247, 38, 114, 2, 102, 139, 30, 54, 2, 102,
139, 14, 114, 2, 102, 139, 54, 42, 2, 30, 7, 102, 139, 62, 70, 2,
232, 129, 251, 232, 167, 252, 102, 97, 144, 31, 7, 195, 102, 80, 102, 83,
102, 81, 102, 139, 30, 74, 2, 102, 139, 200, 102, 193, 232, 3, 102, 131,
225, 7, 102, 3, 216, 102, 184, 1, 0, 0, 0, 102, 211, 224, 103, 132,
3, 15, 132, 4, 0, 248, 235, 2, 144, 249, 102, 89, 102, 91, 102, 88,
195, 103, 128, 123, 8, 1, 15, 132, 4, 0, 102, 43, 192, 195, 103, 102,
141, 115, 16, 103, 102, 139, 86, 8, 102, 59, 194, 15, 135, 11, 0, 103,
102, 139, 22, 102, 59, 194, 15, 131, 4, 0, 102, 43, 192, 195, 103, 3,
94, 16, 102, 43, 246, 103, 128, 59, 0, 15, 132, 62, 0, 232, 129, 0,
102, 3, 241, 232, 57, 0, 102, 3, 202, 102, 59, 193, 15, 140, 33, 0,
102, 139, 209, 102, 80, 103, 102, 15, 182, 11, 102, 139, 193, 102, 131, 224,
15, 102, 193, 233, 4, 102, 3, 217, 102, 3, 216, 102, 67, 102, 88, 235,
196, 102, 43, 200, 102, 43, 194, 102, 3, 198, 195, 102, 43, 192, 195, 102,
43, 201, 103, 138, 11, 128, 225, 15, 102, 131, 249, 0, 15, 133, 4, 0,
102, 43, 201, 195, 102, 83, 102, 82, 102, 3, 217, 103, 102, 15, 190, 19,
102, 73, 102, 75, 102, 131, 249, 0, 15, 132, 13, 0, 102, 193, 226, 8,
103, 138, 19, 102, 75, 102, 73, 235, 235, 102, 139, 202, 102, 90, 102, 91,
195, 102, 83, 102, 82, 102, 43, 210, 103, 138, 19, 102, 131, 226, 15, 102,
43, 201, 103, 138, 11, 192, 233, 4, 102, 131, 249, 0, 15, 133, 8, 0,
102, 43, 201, 102, 90, 102, 91, 195, 102, 3, 218, 102, 3, 217, 103, 102,
15, 190, 19, 102, 73, 102, 75, 102, 131, 249, 0, 15, 132, 13, 0, 102,
193, 226, 8, 103, 138, 19, 102, 75, 102, 73, 235, 235, 102, 139, 202, 102,
90, 102, 91, 195, 102, 11, 201, 15, 133, 1, 0, 195, 102, 81, 102, 86,
103, 131, 62, 97, 15, 140, 12, 0, 103, 131, 62, 122, 15, 143, 4, 0,
103, 131, 46, 32, 102, 131, 198, 2, 226, 230, 102, 94, 102, 89, 195, 102,
80, 102, 81, 102, 139, 208, 102, 161, 50, 2, 103, 102, 141, 88, 16, 103,
3, 67, 4, 103, 102, 141, 64, 16, 102, 139, 218, 232, 68, 249, 102, 11,
192, 15, 132, 5, 0, 102, 89, 102, 89, 195, 102, 161, 54, 2, 102, 11,
192, 15, 133, 8, 0, 102, 89, 102, 89, 102, 51, 192, 195, 102, 139, 22,
54, 2, 103, 102, 141, 82, 16, 103, 102, 139, 66, 24, 102, 51, 210, 102,
247, 54, 110, 2, 102, 51, 246, 102, 80, 102, 86, 102, 88, 102, 94, 102,
59, 198, 15, 132, 58, 0, 102, 86, 102, 64, 102, 80, 102, 72, 232, 27,
254, 114, 232, 232, 235, 253, 102, 90, 102, 94, 102, 89, 102, 91, 102, 83,
102, 81, 102, 86, 102, 82, 102, 161, 70, 2, 103, 102, 141, 64, 24, 232,
208, 248, 102, 11, 192, 116, 196, 102, 89, 102, 89, 102, 89, 102, 89, 195,
102, 89, 102, 89, 102, 51, 192, 195, 102, 81, 102, 80, 102, 184, 5, 0,
0, 0, 30, 7, 102, 139, 249, 232, 141, 253, 102, 139, 193, 102, 187, 32,
0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232,
51, 248, 102, 91, 102, 89, 102, 133, 192, 15, 133, 21, 0, 102, 139, 193,
102, 15, 183, 14, 16, 2, 102, 186, 18, 2, 0, 0, 232, 22, 248, 235,
51, 144, 102, 51, 210, 102, 139, 193, 102, 139, 203, 102, 80, 102, 83, 232,
35, 0, 102, 91, 102, 95, 102, 11, 192, 15, 132, 23, 0, 30, 7, 232,
53, 253, 102, 139, 199, 102, 15, 183, 14, 16, 2, 102, 186, 18, 2, 0,
0, 232, 225, 247, 195, 102, 82, 102, 81, 102, 187, 32, 0, 0, 0, 102,
185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 199, 247, 102, 11,
192, 15, 132, 99, 0, 102, 139, 216, 30, 7, 102, 139, 62, 26, 2, 102,
51, 192, 232, 89, 248, 30, 7, 102, 139, 30, 26, 2, 102, 89, 102, 90,
38, 102, 57, 15, 15, 133, 12, 0, 38, 102, 57, 87, 8, 15, 132, 49,
0, 235, 19, 144, 38, 102, 131, 63, 255, 15, 132, 47, 0, 38, 131, 127,
4, 0, 15, 132, 38, 0, 38, 102, 15, 183, 71, 4, 3, 216, 139, 195,
37, 0, 128, 116, 203, 140, 192, 5, 0, 8, 142, 192, 129, 227, 255, 127,
235, 190, 38, 102, 139, 71, 16, 195, 102, 89, 102, 90, 102, 51, 192, 195,
102, 80, 102, 81, 102, 139, 199, 102, 193, 232, 4, 6, 89, 3, 200, 81,
7, 102, 131, 231, 15, 102, 89, 102, 88, 195, 96, 6, 190, 189, 13, 191,
0, 32, 30, 7, 185, 13, 0, 144, 243, 165, 7, 97, 195, 1, 35, 69,
103, 137, 171, 205, 239, 254, 220, 186, 152, 118, 84, 50, 16, 240, 225, 210,
195, 0, 0, 0, 0, 32, 32, 96, 139, 54, 24, 32, 38, 138, 5, 136,
4, 71, 70, 102, 255, 6, 20, 32, 129, 254, 96, 32, 117, 6, 232, 91,
0, 190, 32, 32, 226, 230, 137, 54, 24, 32, 97, 195, 102, 96, 139, 54,
24, 32, 176, 128, 136, 4, 70, 50, 192, 129, 254, 96, 32, 117, 6, 232,
58, 0, 190, 32, 32, 129, 254, 88, 32, 117, 233, 102, 51, 192, 102, 163,
88, 32, 102, 161, 20, 32, 102, 193, 224, 3, 102, 15, 200, 102, 163, 92,
32, 232, 24, 0, 187, 0, 32, 102, 139, 7, 102, 15, 200, 102, 137, 7,
131, 195, 4, 129, 251, 52, 32, 117, 238, 102, 97, 195, 102, 96, 187, 32,
32, 102, 139, 7, 102, 15, 200, 102, 137, 7, 131, 195, 4, 129, 251, 96,
32, 117, 238, 187, 0, 32, 102, 139, 15, 102, 139, 87, 4, 102, 139, 119,
8, 102, 139, 127, 12, 102, 139, 111, 16, 187, 32, 32, 199, 6, 26, 32,
48, 15, 198, 6, 28, 32, 20, 144, 83, 139, 30, 26, 32, 255, 23, 102,
3, 71, 2, 91, 102, 3, 232, 102, 3, 47, 102, 139, 193, 102, 193, 192,
5, 102, 3, 197, 102, 139, 239, 102, 139, 254, 102, 139, 242, 102, 193, 198,
30, 102, 139, 209, 102, 139, 200, 102, 139, 7, 102, 51, 71, 8, 102, 51,
71, 32, 102, 51, 71, 52, 102, 209, 192, 102, 137, 71, 64, 131, 195, 4,
254, 14, 28, 32, 117, 178, 131, 6, 26, 32, 6, 129, 62, 26, 32, 72,
15, 117, 159, 187, 0, 32, 102, 1, 15, 102, 1, 87, 4, 102, 1, 119,
8, 102, 1, 127, 12, 102, 1, 111, 16, 102, 97, 195, 102, 139, 198, 102,
51, 199, 102, 35, 194, 102, 51, 199, 195, 102, 139, 194, 102, 51, 198, 102,
51, 199, 195, 102, 83, 102, 139, 194, 102, 35, 198, 102, 139, 218, 102, 35,
223, 102, 11, 195, 102, 139, 222, 102, 35, 223, 102, 11, 195, 102, 91, 195,
252, 14, 153, 121, 130, 90, 9, 15, 161, 235, 217, 110, 19, 15, 220, 188,
27, 143, 9, 15, 214, 193, 98, 202, 6, 30, 102, 96, 102, 51, 219, 184,
0, 187, 205, 26, 102, 35, 192, 15, 133, 187, 0, 102, 129, 251, 84, 67,
80, 65, 15, 133, 176, 0, 129, 249, 2, 1, 15, 130, 168, 0, 102, 97,
144, 31, 7, 6, 30, 102, 96, 103, 128, 123, 8, 0, 15, 133, 12, 0,
103, 102, 141, 83, 16, 103, 102, 139, 10, 235, 37, 144, 103, 102, 141, 83,
16, 103, 102, 139, 74, 40, 102, 129, 249, 0, 0, 8, 0, 15, 131, 12,
0, 103, 102, 139, 66, 44, 102, 35, 192, 15, 132, 3, 0, 102, 51, 201,
14, 31, 232, 245, 253, 102, 35, 201, 15, 132, 50, 0, 102, 186, 0, 128,
0, 0, 102, 59, 202, 15, 134, 31, 0, 102, 43, 202, 6, 102, 81, 102,
87, 102, 82, 102, 139, 202, 232, 183, 253, 232, 251, 253, 102, 90, 102, 95,
102, 89, 7, 102, 3, 250, 235, 218, 232, 165, 253, 232, 233, 253, 232, 11,
254, 14, 7, 102, 187, 84, 67, 80, 65, 102, 191, 0, 32, 0, 0, 102,
185, 20, 0, 0, 0, 102, 184, 7, 187, 0, 0, 102, 186, 10, 0, 0,
0, 102, 51, 246, 205, 26, 102, 97, 144, 31, 7, 195, 160, 249, 1, 233,
64, 241, 160, 250, 1, 233, 58, 241
};

View File

@ -1,7 +1,7 @@
#ifndef _NTFS_BOOT_H_
#define _NTFS_BOOT_H_
extern const unsigned char boot_array[3429];
extern const unsigned char boot_array[4136];
#endif /* _NTFS_BOOT_H_ */

View File

@ -45,10 +45,6 @@ mkntfs \- create an NTFS file system
.B \-n
]
[
.B \-N
.I ntfs\-version
]
[
.B \-p
.I part\-start\-sect
]
@ -123,39 +119,6 @@ Set the volume label for the filesystem.
\fB\-C\fR, \fB\-\-enable\-compression\fR
Enable compression on the volume.
.TP
\fB\-c\fR, \fB\-\-cluster\-size\fR BYTES
Specify the size of clusters in bytes. Valid cluster size values are powers of
two, with at least 256, and at most 65536 bytes per cluster. If omitted,
.B mkntfs
determines the
.I cluster\-size
from the volume size. The value is determined as follows:
.TS
box;
lB lB lB
l l r.
Volume size Default cluster size
0 \- 512MB 512 bytes
512MB \- 1GB 1024 bytes
1GB \- 2GB 2048 bytes
2GB + 4096 bytes
.TE
.sp
.sp
Note that the default cluster size is set to be at least equal to the sector
size as a cluster cannot be smaller than a sector. Also, note that values
greater than 4096 have the side effect that compression is disabled on the
volume (due to limitations in the NTFS compression algorithm currently in use
by Windows).
.TP
\fB\-N\fR, \fB\-\-ntfs\-version\fR STRING
Select the version of NTFS you wish to create. This can be "1.2"
(Windows NT 4.0) or "3.1" (Windows XP, Server 2003 and Vista).
Versions are upwards compatible and Windows 2000, which uses version "3.0",
can read/write both.
If this option is omitted then version "3.1" is used.
.TP
\fB\-n\fR, \fB\-\-no\-action\fR
Causes
.B mkntfs
@ -164,6 +127,18 @@ to create a filesystem. All steps of the format are carried out except the
actual writing to the device.
.SS Advanced options
.TP
\fB\-c\fR, \fB\-\-cluster\-size\fR BYTES
Specify the size of clusters in bytes. Valid cluster size values are powers of
two, with at least 256, and at most 65536 bytes per cluster. If omitted,
.B mkntfs
uses 4096 bytes as the default cluster size.
.sp
Note that the default cluster size is set to be at least equal to the sector
size as a cluster cannot be smaller than a sector. Also, note that values
greater than 4096 have the side effect that compression is disabled on the
volume (due to limitations in the NTFS compression algorithm currently in use
by Windows).
.TP
\fB\-s\fR, \fB\-\-sector\-size\fR BYTES
Specify the size of sectors in bytes. Valid sector size values are 256, 512,
1024, 2048 and 4096 bytes per sector. If omitted,

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,8 @@
.\" Copyright (c) 2003\-2005 Richard Russon.
.\" Copyright (c) 2007 Yura Pakhuchiy.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSCAT 8 "November 2005" "ntfs-3g @VERSION@"
.TH NTFSCAT 8 "September 2007" "ntfs-3g @VERSION@"
.SH NAME
ntfscat \- print NTFS files and streams on the standard output
.SH SYNOPSIS
@ -133,5 +134,8 @@ The manual pages are available online at:
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
Read \fBlibntfs\fR(8) for details how to access encrypted files.
.sp
.BR libntfs (8),
.BR ntfsls (8),
.BR ntfsprogs (8)

View File

@ -4,6 +4,7 @@
* Copyright (c) 2003-2005 Richard Russon
* Copyright (c) 2003-2005 Anton Altaparmakov
* Copyright (c) 2003-2005 Szabolcs Szakacsits
* Copyright (c) 2007 Yura Pakhuchiy
*
* This utility will concatenate files and print on the standard output.
*
@ -60,11 +61,12 @@ static struct options opts;
*/
static void version(void)
{
ntfs_log_info("\n%s v%s (libntfs-3g) - Concatenate files and print on the "
"standard output.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("\n%s v%s (libntfs-3g) - Concatenate files and print "
"on the standard output.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c) 2003-2005 Richard Russon\n");
ntfs_log_info("Copyright (c) 2003-2005 Anton Altaparmakov\n");
ntfs_log_info("Copyright (c) 2003-2005 Szabolcs Szakacsits\n");
ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -86,7 +88,8 @@ static void usage(void)
" -q, --quiet Less output\n"
" -V, --version Version information\n"
" -v, --verbose More output\n\n",
//" -r --raw Display the compressed or encrypted file",
// Does not work for compressed files at present so leave undocumented...
// " -r --raw Display the raw data (e.g. for compressed or encrypted file)",
EXEC_NAME);
ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
}
@ -131,14 +134,14 @@ static int parse_attribute(const char *value, ATTR_TYPES *attr)
for (i = 0; attr_name[i]; i++) {
if ((strcmp(value, attr_name[i]) == 0) ||
(strcmp(value, attr_name[i] + 1) == 0)) {
*attr = (ATTR_TYPES) ((i+1)*16);
*attr = (ATTR_TYPES)cpu_to_le32((i + 1) * 16);
return 1;
}
}
num = strtol(value, NULL, 0);
if ((num > 0) && (num < 257)) {
*attr = (ATTR_TYPES) num;
*attr = (ATTR_TYPES)cpu_to_le32(num);
return 1;
}
@ -156,7 +159,7 @@ static int parse_attribute(const char *value, ATTR_TYPES *attr)
*/
static int parse_options(int argc, char **argv)
{
static const char *sopt = "-a:fh?i:n:qVv";
static const char *sopt = "-a:fh?i:n:qVvr";
static const struct option lopt[] = {
{ "attribute", required_argument, NULL, 'a' },
{ "attribute-name", required_argument, NULL, 'n' },
@ -166,6 +169,7 @@ static int parse_options(int argc, char **argv)
{ "quiet", no_argument, NULL, 'q' },
{ "version", no_argument, NULL, 'V' },
{ "verbose", no_argument, NULL, 'v' },
{ "raw", no_argument, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
@ -179,7 +183,7 @@ static int parse_options(int argc, char **argv)
opterr = 0; /* We'll handle the errors, thank you. */
opts.inode = -1;
opts.attr = -1;
opts.attr = cpu_to_le32(-1);
opts.attr_name = NULL;
opts.attr_name_len = 0;
@ -191,13 +195,15 @@ static int parse_options(int argc, char **argv)
} else if (!opts.file) {
opts.file = argv[optind - 1];
} else {
ntfs_log_error("You must specify exactly one file.\n");
ntfs_log_error("You must specify exactly one "
"file.\n");
err++;
}
break;
case 'a':
if (opts.attr != (ATTR_TYPES)-1) {
ntfs_log_error("You must specify exactly one attribute.\n");
if (opts.attr != cpu_to_le32(-1)) {
ntfs_log_error("You must specify exactly one "
"attribute.\n");
} else if (parse_attribute(optarg, &attr) > 0) {
opts.attr = attr;
break;
@ -232,7 +238,8 @@ static int parse_options(int argc, char **argv)
opts.attr_name_len = ntfs_mbstoucs_libntfscompat(optarg,
&opts.attr_name, 0);
if (opts.attr_name_len < 0) {
ntfs_log_perror("Invalid attribute name '%s'", optarg);
ntfs_log_perror("Invalid attribute name '%s'",
optarg);
usage();
}
@ -247,6 +254,9 @@ static int parse_options(int argc, char **argv)
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
case 'r':
opts.raw = TRUE;
break;
default:
ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
err++;
@ -312,8 +322,7 @@ static int index_get_size(ntfs_inode *inode)
return 0; // not a directory
iroot = (INDEX_ROOT*)((u8*)attr90 + le16_to_cpu(attr90->value_offset));
return iroot->index_block_size;
return le32_to_cpu(iroot->index_block_size);
}
/**
@ -335,7 +344,8 @@ static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type,
attr = ntfs_attr_open(inode, type, name, namelen);
if (!attr) {
ntfs_log_error("Cannot find attribute type 0x%lx.\n", (long) type);
ntfs_log_error("Cannot find attribute type 0x%x.\n",
le32_to_cpu(type));
free(buffer);
return 1;
}
@ -349,9 +359,10 @@ static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type,
offset = 0;
for (;;) {
if (block_size > 0) {
if (!opts.raw && block_size > 0) {
// These types have fixup
bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer);
if (bytes_read > 0)
bytes_read *= block_size;
} else {
bytes_read = ntfs_attr_pread(attr, offset, bufsize, buffer);
@ -399,7 +410,8 @@ int main(int argc, char *argv[])
utils_set_locale();
vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force);
vol = utils_mount_volume(opts.device, MS_RDONLY |
(opts.force ? MS_RECOVER : 0));
if (!vol) {
ntfs_log_perror("ERROR: couldn't mount volume");
return 1;
@ -416,7 +428,7 @@ int main(int argc, char *argv[])
}
attr = AT_DATA;
if (opts.attr != (ATTR_TYPES)-1)
if (opts.attr != cpu_to_le32(-1))
attr = opts.attr;
result = cat(vol, inode, attr, opts.attr_name, opts.attr_name_len);

View File

@ -38,6 +38,7 @@ struct options {
int force; /* Override common sense */
int quiet; /* Less output */
int verbose; /* Extra output */
BOOL raw; /* Raw data output */
};
#endif /* _NTFSCAT_H_ */

868
ntfsprogs/ntfsck.c Normal file
View File

@ -0,0 +1,868 @@
/**
* ntfsck - Part of the Linux-NTFS project.
*
* Copyright (c) 2006 Yuval Fledel
*
* This utility will check and fix errors on an NTFS volume.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <ntfs-3g/layout.h>
#include <ntfs-3g/bitmap.h>
#include <ntfs-3g/endians.h>
#include <ntfs-3g/bootsect.h>
#include <ntfs-3g/misc.h>
#include "cluster.h"
#include "utils.h"
#define RETURN_FS_ERRORS_CORRECTED (1)
#define RETURN_SYSTEM_NEEDS_REBOOT (2)
#define RETURN_FS_ERRORS_LEFT_UNCORRECTED (4)
#define RETURN_OPERATIONAL_ERROR (8)
#define RETURN_USAGE_OR_SYNTAX_ERROR (16)
#define RETURN_CANCELLED_BY_USER (32)
/* Where did 64 go? */
#define RETURN_SHARED_LIBRARY_ERROR (128)
/* todo: command line: (everything is optional)
* fsck-frontend options:
* -C [fd] : display progress bar (send it to the file descriptor if specified)
* -T : don't show the title on startup
* fsck-checker options:
* -a : auto-repair. no questions. (optional: if marked clean and -f not specified, just check if mounable)
* -p : auto-repair safe. no questions (optional: same)
* -n : only check. no repair.
* -r : interactively repair.
* -y : always yes.
* -v : verbose.
* -V : version.
* taken from fsck.ext2
* -b sb : use the superblock from sb. For corrupted volumes. (do we want separete boot/mft options?)
* -c : use badblocks(8) to find bad blocks (R/O mode) and add the findings to $Bad.
* -C fd : write competion info to fd. If 0, print a completion bar.
* -d : debugging output.
* -D : rebalance indices.
* -f : force checking even if marked clean.
* -F : flush buffers before beginning. (for time-benchmarking)
* -k : When used with -c, don't erase previous $Bad items.
* -n : Open fs as readonly. assume always no. (why is it needed if -r is not specified?)
* -t : Print time statistics.
* taken from fsck.reiserfs
* --rebuild-sb : try to find $MFT start and rebuild the boot sector.
* --rebuild-tree : scan for items and rebuild the indices that point to them (0x30, $SDS, etc.)
* --clean-reserved: zero rezerved fields. (use with care!)
* --adjust-size -z: insert a sparse hole if the data_size is larger than the size marked in the runlist.
* --logfile file : report corruptions (unlike other errors) to a file instead of stderr.
* --nolog : don't report corruptions at all.
* --quiet -q : no progress bar.
* taken from fsck.msdos
* -w : flush after every write.
* - do n passes. (only 2 in fsck.msdos. second should not report errors. Bonus: stop when error list does not change)
* taken from fsck.jfs
* --omit-journal-reply: self-descriptive (why would someone do that?)
* --replay-journal-only: self-descriptive. don't check otherwise.
* taken from fsck.xfs
* -s : only serious errors should be reported.
* -i ino : verbose behaviour only for inode ino.
* -b bno : verbose behaviour only for cluster bno.
* -L : zero log.
* inspired by others
* - don't do cluster accounting.
* - don't do mft record accounting.
* - don't do file names accounting.
* - don't do security_id accounting.
* - don't check acl inheritance problems.
* - undelete unused mft records. (bonus: different options for 100% salvagable and less)
* - error-level-report n: only report errors above this error level
* - error-level-repair n: only repair errors below this error level
* - don't fail on ntfsclone metadata pruning.
* signals:
* SIGUSR1 : start displaying progress bar
* SIGUSR2 : stop displaying progress bar.
*/
/* Assuming NO_NTFS_DEVICE_DEFAULT_IO_OPS is not set */
static int errors = 0;
static int unsupported = 0;
static short bytes_per_sector, sectors_per_cluster;
//static s64 mft_offset, mftmirr_offset;
static s64 current_mft_record;
/**
* This is just a preliminary volume.
* Filled while checking the boot sector and used in the preliminary MFT check.
*/
static ntfs_volume vol;
static runlist_element *mft_rl, *mft_bitmap_rl;
#define check_failed(FORMAT, ARGS...) \
do { \
errors++; \
ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__, \
NTFS_LOG_LEVEL_ERROR,NULL,FORMAT,##ARGS); \
} while (0);
/**
* 0 success.
* 1 fail.
*/
static int assert_u32_equal(u32 val, u32 ok, const char *name)
{
if (val!=ok) {
check_failed("Assertion failed for '%lld:%s'. should be 0x%x, "
"was 0x%x.\n", current_mft_record, name,
(int)ok, (int)val);
//errors++;
return 1;
}
return 0;
}
static int assert_u32_noteq(u32 val, u32 wrong, const char *name)
{
if (val==wrong) {
check_failed("Assertion failed for '%lld:%s'. should not be "
"0x%x.\n", current_mft_record, name, (int)wrong);
return 1;
}
return 0;
}
static int assert_u32_lesseq(u32 val1, u32 val2, const char *name)
{
if (val1 > val2) {
check_failed("Assertion failed for '%s'. 0x%x > 0x%x\n",
name, (int)val1, (int)val2);
//errors++;
return 1;
}
return 0;
}
static int assert_u32_less(u32 val1, u32 val2, const char *name)
{
if (val1 >= val2) {
check_failed("Assertion failed for '%s'. 0x%x >= 0x%x\n",
name, (int)val1, (int)val2);
//errors++;
return 1;
}
return 0;
}
/**
* Return: 0 ok, 1 error.
*
* todo: may we use ntfs_boot_sector_is_ntfs() instead?
* It already does the checks but will not be able to fix anything.
*/
static BOOL verify_boot_sector(struct ntfs_device *dev)
{
u8 buf[512];
NTFS_BOOT_SECTOR *ntfs_boot = (NTFS_BOOT_SECTOR *)&buf;
//u32 bytes_per_cluster;
current_mft_record = 9;
if (dev->d_ops->pread(dev, buf, sizeof(buf), 0)!=sizeof(buf)) {
check_failed("Failed to read boot sector.\n");
return 1;
}
if ((buf[0]!=0xeb) ||
((buf[1]!=0x52) && (buf[1]!=0x5b)) ||
(buf[2]!=0x90)) {
check_failed("Boot sector: Bad jump.\n");
}
if (ntfs_boot->oem_id != NTFS_SB_MAGIC) {
check_failed("Boot sector: Bad NTFS magic.\n");
}
bytes_per_sector = le16_to_cpu(ntfs_boot->bpb.bytes_per_sector);
if (!bytes_per_sector) {
check_failed("Boot sector: Bytes per sector is 0.\n");
}
if (bytes_per_sector%512) {
check_failed("Boot sector: Bytes per sector is not a multiple"
" of 512.\n");
}
sectors_per_cluster = ntfs_boot->bpb.sectors_per_cluster;
// todo: if partition, query bios and match heads/tracks? */
// Initialize some values from vol. We will need those later.
ntfs_boot_sector_parse(&vol, (NTFS_BOOT_SECTOR *)buf);
vol.dev = dev;
return 0;
}
/**
* Load the runlist of the <attr_type> attribute.
*
* Return NULL if an error.
* The caller is responsible on freeing the allocated memory if the result is not NULL.
*
* Set size_of_file_record to some reasonable size when in doubt (the Windows default is 1024.)
*
* attr_type must be little endian.
*
* This function has code duplication with check_file_record() and
* check_attr_record() but its goal is to be less strict. Thus the
* duplicated checks are the minimal required for not crashing.
*
* Assumes dev is open.
*/
static runlist *load_runlist(struct ntfs_device *dev, s64 offset_to_file_record, u32 attr_type, u32 size_of_file_record)
{
u8 *buf;
u16 attrs_offset;
u32 length;
ATTR_RECORD *attr_rec;
if (size_of_file_record<22) // offset to attrs_offset
return NULL;
buf = (u8*)ntfs_malloc(size_of_file_record);
if (!buf)
return NULL;
if (dev->d_ops->pread(dev, buf, size_of_file_record, offset_to_file_record)!=size_of_file_record) {
check_failed("Failed to read file record at offset %lld (0x%llx).\n", offset_to_file_record, offset_to_file_record);
return NULL;
}
attrs_offset = le16_to_cpu(((MFT_RECORD*)buf)->attrs_offset);
// first attribute must be after the header.
if (attrs_offset<42) {
check_failed("First attribute must be after the header (%u).\n", (int)attrs_offset);
}
attr_rec = (ATTR_RECORD *)(buf + attrs_offset);
//printf("uv1.\n");
while ((u8*)attr_rec<=buf+size_of_file_record-4) {
//printf("Attr type: 0x%x.\n", attr_rec->type);
// Check attribute record. (Only what is in the buffer)
if (attr_rec->type==AT_END) {
check_failed("Attribute 0x%x not found in file record at offset %lld (0x%llx).\n", (int)le32_to_cpu(attr_rec->type), offset_to_file_record, offset_to_file_record);
return NULL;
}
if ((u8*)attr_rec>buf+size_of_file_record-8) {
// not AT_END yet no room for the length field.
check_failed("Attribute 0x%x is not AT_END, yet no "
"room for the length field.\n",
(int)le32_to_cpu(attr_rec->type));
return NULL;
}
length = le32_to_cpu(attr_rec->length);
// Check that this attribute does not overflow the mft_record
if ((u8*)attr_rec+length >= buf+size_of_file_record) {
check_failed("Attribute (0x%x) is larger than FILE record at offset %lld (0x%llx).\n",
(int)le32_to_cpu(attr_rec->type), offset_to_file_record, offset_to_file_record);
return NULL;
}
// todo: what ATTRIBUTE_LIST (0x20)?
if (attr_rec->type==attr_type) {
// Eurika!
// ntfs_mapping_pairs_decompress only use two values from vol. Just fake it.
// todo: it will also use vol->major_ver if defined(DEBUG). But only for printing purposes.
// Assume ntfs_boot_sector_parse() was called.
return ntfs_mapping_pairs_decompress(&vol, attr_rec, NULL);
}
attr_rec = (ATTR_RECORD*)((u8*)attr_rec+length);
}
// If we got here, there was an overflow.
check_failed("file record corrupted at offset %lld (0x%llx).\n", offset_to_file_record, offset_to_file_record);
return NULL;
}
/**
* Return: >=0 last VCN
* LCN_EINVAL error.
*/
static VCN get_last_vcn(runlist *rl)
{
VCN res;
if (!rl)
return LCN_EINVAL;
res = LCN_EINVAL;
while (rl->length) {
ntfs_log_verbose("vcn: %lld, length: %lld.\n", rl->vcn,
rl->length);
if (rl->vcn<0)
res = rl->vcn;
else
res = rl->vcn + rl->length;
rl++;
}
return res;
}
static u32 mft_bitmap_records;
static u8 *mft_bitmap_buf;
/**
* Assumes mft_bitmap_rl is initialized.
* return: 0 ok.
* RETURN_OPERATIONAL_ERROR on error.
*/
static int mft_bitmap_load(struct ntfs_device *dev)
{
VCN vcn;
u32 mft_bitmap_length;
vcn = get_last_vcn(mft_bitmap_rl);
if (vcn<=LCN_EINVAL) {
mft_bitmap_buf = NULL;
/* This case should not happen, not even with on-disk errors */
goto error;
}
mft_bitmap_length = vcn * vol.cluster_size;
mft_bitmap_records = 8 * mft_bitmap_length * vol.cluster_size /
vol.mft_record_size;
//printf("sizes: %d, %d.\n", mft_bitmap_length, mft_bitmap_records);
mft_bitmap_buf = (u8*)ntfs_malloc(mft_bitmap_length);
if (!mft_bitmap_buf)
goto error;
if (ntfs_rl_pread(&vol, mft_bitmap_rl, 0, mft_bitmap_length,
mft_bitmap_buf)!=mft_bitmap_length)
goto error;
return 0;
error:
mft_bitmap_records = 0;
ntfs_log_error("Could not load $MFT/Bitmap.\n");
return RETURN_OPERATIONAL_ERROR;
}
/**
* -1 Error.
* 0 Unused record
* 1 Used record
*
* Assumes mft_bitmap_rl was initialized.
*/
static int mft_bitmap_get_bit(s64 mft_no)
{
if (mft_no>=mft_bitmap_records)
return -1;
return ntfs_bit_get(mft_bitmap_buf, mft_no);
}
/**
* @attr_rec: The attribute record to check
* @mft_rec: The parent FILE record.
* @buflen: The size of the FILE record.
*
* Return:
* NULL: Fatal error occured. Not sure where is the next record.
* otherwise: pointer to the next attribute record.
*
* The function only check fields that are inside this attr record.
*
* Assumes mft_rec is current_mft_record.
*/
static ATTR_REC *check_attr_record(ATTR_REC *attr_rec, MFT_RECORD *mft_rec,
u16 buflen)
{
u16 name_offset;
u16 attrs_offset = le16_to_cpu(mft_rec->attrs_offset);
u32 attr_type = le32_to_cpu(attr_rec->type);
u32 length = le32_to_cpu(attr_rec->length);
// Check that this attribute does not overflow the mft_record
if ((u8*)attr_rec+length >= ((u8*)mft_rec)+buflen) {
check_failed("Attribute (0x%x) is larger than FILE record (%lld).\n",
(int)attr_type, current_mft_record);
return NULL;
}
// Attr type must be a multiple of 0x10 and 0x10<=x<=0x100.
if ((attr_type & ~0x0F0) && (attr_type != 0x100)) {
check_failed("Unknown attribute type 0x%x.\n",
(int)attr_type);
goto check_attr_record_next_attr;
}
if (length<24) {
check_failed("Attribute %lld:0x%x Length too short (%u).\n",
current_mft_record, (int)attr_type, (int)length);
goto check_attr_record_next_attr;
}
// If this is the first attribute:
// todo: instance number must be smaller than next_instance.
if ((u8*)attr_rec == ((u8*)mft_rec) + attrs_offset) {
if (!mft_rec->base_mft_record)
assert_u32_equal(attr_type, 0x10,
"First attribute type");
// The following not always holds.
// attr 0x10 becomes instance 1 and attr 0x40 becomes 0.
//assert_u32_equal(attr_rec->instance, 0,
// "First attribute instance number");
} else {
assert_u32_noteq(attr_type, 0x10,
"Not-first attribute type");
// The following not always holds.
//assert_u32_noteq(attr_rec->instance, 0,
// "Not-first attribute instance number");
}
//if (current_mft_record==938 || current_mft_record==1683 || current_mft_record==3152 || current_mft_record==22410)
//printf("Attribute %lld:0x%x instance: %u isbase:%d.\n",
// current_mft_record, (int)attr_type, (int)le16_to_cpu(attr_rec->instance), (int)mft_rec->base_mft_record);
// todo: instance is unique.
// Check flags.
if (attr_rec->flags & ~(const_cpu_to_le16(0xc0ff))) {
check_failed("Attribute %lld:0x%x Unknown flags (0x%x).\n",
current_mft_record, (int)attr_type,
(int)le16_to_cpu(attr_rec->flags));
}
if (attr_rec->non_resident>1) {
check_failed("Attribute %lld:0x%x Unknown non-resident "
"flag (0x%x).\n", current_mft_record,
(int)attr_type, (int)attr_rec->non_resident);
goto check_attr_record_next_attr;
}
name_offset = le16_to_cpu(attr_rec->name_offset);
/*
* todo: name must be legal unicode.
* Not really, information below in urls is about filenames, but I
* believe it also applies to attribute names. (Yura)
* http://blogs.msdn.com/michkap/archive/2006/09/24/769540.aspx
* http://blogs.msdn.com/michkap/archive/2006/09/10/748699.aspx
*/
if (attr_rec->non_resident) {
// Non-Resident
// Make sure all the fields exist.
if (length<64) {
check_failed("Non-resident attribute %lld:0x%x too short (%u).\n",
current_mft_record, (int)attr_type, (int)length);
goto check_attr_record_next_attr;
}
if (attr_rec->compression_unit && (length<72)) {
check_failed("Compressed attribute %lld:0x%x too short (%u).\n",
current_mft_record, (int)attr_type, (int)length);
goto check_attr_record_next_attr;
}
// todo: name comes before mapping pairs, and after the header.
// todo: length==mapping_pairs_offset+length of compressed mapping pairs.
// todo: mapping_pairs_offset is 8-byte aligned.
// todo: lowest vcn <= highest_vcn
// todo: if base record -> lowest vcn==0
// todo: lowest_vcn!=0 -> attribute list is used.
// todo: lowest_vcn & highest_vcn are in the drive (0<=x<total clusters)
// todo: mapping pairs agree with highest_vcn.
// todo: compression unit == 0 or 4.
// todo: reserved1 == 0.
// todo: if not compressed nor sparse, initialized_size <= allocated_size and data_size <= allocated_size.
// todo: if compressed or sparse, allocated_size <= initialized_size and allocated_size <= data_size
// todo: if mft_no!=0 and not compressed/sparse, data_size==initialized_size.
// todo: if mft_no!=0 and compressed/sparse, allocated_size==initialized_size.
// todo: what about compressed_size if compressed?
// todo: attribute must not be 0x10, 0x30, 0x40, 0x60, 0x70, 0x90, 0xd0 (not sure about 0xb0, 0xe0, 0xf0)
} else {
u16 value_offset = le16_to_cpu(attr_rec->value_offset);
u32 value_length = le32_to_cpu(attr_rec->value_length);
// Resident
if (attr_rec->name_length) {
if (name_offset < 24)
check_failed("Resident attribute with "
"name intersecting header.\n");
if (value_offset < name_offset +
attr_rec->name_length)
check_failed("Named resident attribute "
"with value before name.\n");
}
// if resident, length==value_length+value_offset
//assert_u32_equal(le32_to_cpu(attr_rec->value_length)+
// value_offset, length,
// "length==value_length+value_offset");
// if resident, length==value_length+value_offset
if (value_length+value_offset > length) {
check_failed("value_length(%d)+value_offset(%d)>length(%d) for attribute 0x%x.\n", (int)value_length, (int)value_offset, (int)length, (int)attr_type);
return NULL;
}
// Check resident_flags.
if (attr_rec->resident_flags>0x01) {
check_failed("Unknown resident flags (0x%x) for attribute 0x%x.\n", (int)attr_rec->resident_flags, (int)attr_type);
} else if (attr_rec->resident_flags && (attr_type!=0x30)) {
check_failed("Resident flags mark attribute 0x%x as indexed.\n", (int)attr_type);
}
// reservedR is 0.
assert_u32_equal(attr_rec->reservedR, 0, "Resident Reserved");
// todo: attribute must not be 0xa0 (not sure about 0xb0, 0xe0, 0xf0)
// todo: check content well-formness per attr_type.
}
return 0;
check_attr_record_next_attr:
return (ATTR_REC *)(((u8 *)attr_rec) + length);
}
/**
* All checks that can be satisfied only by data from the buffer.
* No other [MFT records/metadata files] are required.
*
* The buffer is changed by removing the Update Sequence.
*
* Return:
* 0 Everything's cool.
* else Consider this record as damaged.
*/
static BOOL check_file_record(u8 *buffer, u16 buflen)
{
u16 usa_count, usa_ofs, attrs_offset, usa;
u32 bytes_in_use, bytes_allocated, i;
MFT_RECORD *mft_rec = (MFT_RECORD *)buffer;
ATTR_REC *attr_rec;
// check record magic
assert_u32_equal(mft_rec->magic, magic_FILE, "FILE record magic");
// todo: records 16-23 must be filled in order.
// todo: what to do with magic_BAAD?
// check usa_count+offset to update seq <= attrs_offset <
// bytes_in_use <= bytes_allocated <= buflen.
usa_ofs = le16_to_cpu(mft_rec->usa_ofs);
usa_count = le16_to_cpu(mft_rec->usa_count);
attrs_offset = le16_to_cpu(mft_rec->attrs_offset);
bytes_in_use = le32_to_cpu(mft_rec->bytes_in_use);
bytes_allocated = le32_to_cpu(mft_rec->bytes_allocated);
if (assert_u32_lesseq(usa_ofs+usa_count, attrs_offset,
"usa_ofs+usa_count <= attrs_offset") ||
assert_u32_less(attrs_offset, bytes_in_use,
"attrs_offset < bytes_in_use") ||
assert_u32_lesseq(bytes_in_use, bytes_allocated,
"bytes_in_use <= bytes_allocated") ||
assert_u32_lesseq(bytes_allocated, buflen,
"bytes_allocated <= max_record_size")) {
return 1;
}
// We should know all the flags.
if (mft_rec->flags>0xf) {
check_failed("Unknown MFT record flags (0x%x).\n",
(unsigned int)mft_rec->flags);
}
// todo: flag in_use must be on.
// Remove update seq & check it.
usa = *(u16*)(buffer+usa_ofs); // The value that should be at the end of every sector.
assert_u32_equal(usa_count-1, buflen/bytes_per_sector, "USA length");
for (i=1;i<usa_count;i++) {
u16 *fixup = (u16*)(buffer+bytes_per_sector*i-2); // the value at the end of the sector.
u16 saved_val = *(u16*)(buffer+usa_ofs+2*i); // the actual data value that was saved in the us array.
assert_u32_equal(*fixup, usa, "fixup");
*fixup = saved_val; // remove it.
}
attr_rec = (ATTR_REC *)(buffer + attrs_offset);
while ((u8*)attr_rec<=buffer+buflen-4) {
// Check attribute record. (Only what is in the buffer)
if (attr_rec->type==AT_END) {
// Done.
return 0;
}
if ((u8*)attr_rec>buffer+buflen-8) {
// not AT_END yet no room for the length field.
check_failed("Attribute 0x%x is not AT_END, yet no "
"room for the length field.\n",
(int)le32_to_cpu(attr_rec->type));
return 1;
}
attr_rec = check_attr_record(attr_rec, mft_rec, buflen);
if (!attr_rec)
return 1;
}
// If we got here, there was an overflow.
return 1;
// todo: an attribute should be at the offset to first attribute, and the offset should be inside the buffer. It should have the value of "next attribute id".
// todo: if base record, it should start with attribute 0x10.
// Highlevel check of attributes.
// todo: Attributes are well-formed.
// todo: Room for next attribute in the end of the previous record.
return FALSE;
}
static void replay_log(ntfs_volume *vol)
{
// At this time, only check that the log is fully replayed.
ntfs_log_warning("Unsupported: replay_log()\n");
// todo: if logfile is clean, return success.
unsupported++;
}
static void verify_mft_record(ntfs_volume *vol, s64 mft_num)
{
u8 *buffer;
int is_used;
current_mft_record = mft_num;
is_used = mft_bitmap_get_bit(mft_num);
if (is_used<0) {
ntfs_log_error("Error getting bit value for record %lld.\n", mft_num);
} else if (!is_used) {
ntfs_log_verbose("Record %lld unused. Skipping.\n", mft_num);
return;
}
buffer = ntfs_malloc(vol->mft_record_size);
if (!buffer)
goto verify_mft_record_error;
ntfs_log_verbose("MFT record %lld\n", mft_num);
if (ntfs_attr_pread(vol->mft_na, mft_num*vol->mft_record_size, vol->mft_record_size, buffer) < 0) {
ntfs_log_perror("Couldn't read $MFT record %lld", mft_num);
goto verify_mft_record_error;
}
check_file_record(buffer, vol->mft_record_size);
// todo: if offset to first attribute >= 0x30, number of mft record should match.
// todo: Match the "record is used" with the mft bitmap.
// todo: if this is not base, check that the parent is a base, and is in use, and pointing to this record.
// todo: if base record: for each extent record:
// todo: verify_file_record
// todo: hard link count should be the number of 0x30 attributes.
// todo: Order of attributes.
// todo: make sure compression_unit is the same.
return;
verify_mft_record_error:
if (buffer)
free(buffer);
errors++;
}
/**
* This function serves as bootstraping for the more comprehensive checks.
* It will load the MFT runlist and MFT/Bitmap runlist.
* It should not depend on other checks or we may have a circular dependancy.
* Also, this loadng must be forgiving, unlike the comprehensive checks.
*/
static int verify_mft_preliminary(struct ntfs_device *dev)
{
current_mft_record = 0;
s64 mft_offset, mftmirr_offset;
int res;
ntfs_log_trace("Entering verify_mft_preliminary().\n");
// todo: get size_of_file_record from boot sector
// Load the first segment of the $MFT/DATA runlist.
mft_offset = vol.mft_lcn * vol.cluster_size;
mftmirr_offset = vol.mftmirr_lcn * vol.cluster_size;
mft_rl = load_runlist(dev, mft_offset, AT_DATA, 1024);
if (!mft_rl) {
check_failed("Loading $MFT runlist failed. Trying $MFTMirr.\n");
mft_rl = load_runlist(dev, mftmirr_offset, AT_DATA, 1024);
}
if (!mft_rl) {
check_failed("Loading $MFTMirr runlist failed too. Aborting.\n");
return RETURN_FS_ERRORS_LEFT_UNCORRECTED | RETURN_OPERATIONAL_ERROR;
}
// TODO: else { recover $MFT } // Use $MFTMirr to recover $MFT.
// todo: support loading the next runlist extents when ATTRIBUTE_LIST is used on $MFT.
// If attribute list: Gradually load mft runlist. (parse runlist from first file record, check all referenced file records, continue with the next file record). If no attribute list, just load it.
// Load the runlist of $MFT/Bitmap.
// todo: what about ATTRIBUTE_LIST? Can we reuse code?
mft_bitmap_rl = load_runlist(dev, mft_offset, AT_BITMAP, 1024);
if (!mft_bitmap_rl) {
check_failed("Loading $MFT/Bitmap runlist failed. Trying $MFTMirr.\n");
mft_bitmap_rl = load_runlist(dev, mftmirr_offset, AT_BITMAP, 1024);
}
if (!mft_bitmap_rl) {
check_failed("Loading $MFTMirr/Bitmap runlist failed too. Aborting.\n");
return RETURN_FS_ERRORS_LEFT_UNCORRECTED;
// todo: rebuild the bitmap by using the "in_use" file record flag or by filling it with 1's.
}
/* Load $MFT/Bitmap */
if ((res = mft_bitmap_load(dev)))
return res;
return -1; /* FIXME: Just added to fix compiler warning without
thinking about what should be here. (Yura) */
}
static void check_volume(ntfs_volume *vol)
{
s64 mft_num, nr_mft_records;
ntfs_log_warning("Unsupported: check_volume()\n");
unsupported++;
// For each mft record, verify that it contains a valid file record.
nr_mft_records = vol->mft_na->initialized_size >>
vol->mft_record_size_bits;
ntfs_log_info("Checking %lld MFT records.\n", nr_mft_records);
for (mft_num=0; mft_num < nr_mft_records; mft_num++) {
verify_mft_record(vol, mft_num);
}
// todo: Check metadata files.
// todo: Second pass on mft records. Now check the contents as well.
// todo: When going through runlists, build a bitmap.
// todo: cluster accounting.
return;
}
static int reset_dirty(ntfs_volume *vol)
{
u16 flags;
if (!(vol->flags | VOLUME_IS_DIRTY))
return 0;
ntfs_log_verbose("Resetting dirty flag.\n");
flags = vol->flags & ~VOLUME_IS_DIRTY;
if (ntfs_volume_write_flags(vol, flags)) {
ntfs_log_error("Error setting volume flags.\n");
return -1;
}
return 0;
}
/**
* main - Does just what C99 claim it does.
*
* For more details on arguments and results, check the man page.
*/
int main(int argc, char **argv)
{
struct ntfs_device *dev;
ntfs_volume *vol;
const char *name;
int ret;
if (argc != 2)
return RETURN_USAGE_OR_SYNTAX_ERROR;
name = argv[1];
ntfs_log_set_handler(ntfs_log_handler_outerr);
//ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_PROGRESS);
/* Allocate an ntfs_device structure. */
dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL);
if (!dev)
return RETURN_OPERATIONAL_ERROR;
if (dev->d_ops->open(dev, O_RDONLY)) { //O_RDWR/O_RDONLY?
ntfs_log_perror("Error opening partition device");
ntfs_device_free(dev);
return RETURN_OPERATIONAL_ERROR;
}
if ((ret = verify_boot_sector(dev))) {
dev->d_ops->close(dev);
return ret;
}
ntfs_log_verbose("Boot sector verification complete. Proceeding to $MFT");
verify_mft_preliminary(dev);
/* ntfs_device_mount() expects the device to be closed. */
if (dev->d_ops->close(dev))
ntfs_log_perror("Failed to close the device.");
// at this point we know that the volume is valid enough for mounting.
/* Call ntfs_device_mount() to do the actual mount. */
vol = ntfs_device_mount(dev, MS_RDONLY);
if (!vol) {
ntfs_device_free(dev);
return 2;
}
replay_log(vol);
if (vol->flags & VOLUME_IS_DIRTY)
ntfs_log_warning("Volume is dirty.\n");
check_volume(vol);
if (errors)
ntfs_log_info("Errors found.\n");
if (unsupported)
ntfs_log_info("Unsupported cases found.\n");
if (!errors && !unsupported) {
reset_dirty(vol);
}
ntfs_umount(vol, FALSE);
if (errors)
return 2;
if (unsupported)
return 1;
return 0;
}

View File

@ -2,7 +2,7 @@
* ntfsclone - Part of the Linux-NTFS project.
*
* Copyright (c) 2003-2006 Szabolcs Szakacsits
* Copyright (c) 2004-2005 Anton Altaparmakov
* Copyright (c) 2004-2006 Anton Altaparmakov
* Special image format support copyright (c) 2004 Per Olofsson
*
* Clone NTFS data and/or metadata to a sparse file, image, device or stdout.
@ -55,6 +55,12 @@
#include <getopt.h>
#endif
/*
* FIXME: ntfsclone do bad things about endians handling. Fix it and remove
* this note and define.
*/
#define NTFS_DO_NOT_CHECK_ENDIANS
#include "debug.h"
#include "types.h"
#include "support.h"
@ -73,6 +79,7 @@
#include "ntfstime.h"
#include "utils.h"
/* #include "version.h" */
#include "misc.h"
#if defined(linux) && defined(_IO) && !defined(BLKGETSIZE)
#define BLKGETSIZE _IO(0x12,96) /* Get device size in 512-byte blocks. */
@ -95,7 +102,7 @@ static const char *dirty_volume_msg =
"Volume '%s' is scheduled for a check or it was shutdown \n"
"uncleanly. Please boot Windows or use the --force option to progress.\n";
struct {
static struct {
int verbose;
int quiet;
int debug;
@ -116,7 +123,6 @@ struct {
struct bitmap {
s64 size;
u8 *bm;
u8 padding[4]; /* Unused: padding to 64 bit. */
};
struct progress_bar {
@ -140,24 +146,44 @@ struct ntfs_walk_cluster {
};
ntfs_volume *vol = NULL;
struct bitmap lcn_bitmap;
static ntfs_volume *vol = NULL;
static struct bitmap lcn_bitmap;
int fd_in;
int fd_out;
FILE *msg_out = NULL;
static int fd_in;
static int fd_out;
static FILE *msg_out = NULL;
int wipe = 0;
unsigned int nr_used_mft_records = 0;
unsigned int wiped_unused_mft_data = 0;
unsigned int wiped_unused_mft = 0;
unsigned int wiped_resident_data = 0;
unsigned int wiped_timestamp_data = 0;
static int wipe = 0;
static unsigned int nr_used_mft_records = 0;
static unsigned int wiped_unused_mft_data = 0;
static unsigned int wiped_unused_mft = 0;
static unsigned int wiped_resident_data = 0;
static unsigned int wiped_timestamp_data = 0;
static BOOL image_is_host_endian = FALSE;
#define IMAGE_MAGIC "\0ntfsclone-image"
#define IMAGE_MAGIC_SIZE 16
struct {
/* This is the first endianness safe format version. */
#define NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE 10
#define NTFSCLONE_IMG_VER_MINOR_ENDIANNESS_SAFE 0
/*
* Set the version to 10.0 to avoid colisions with old ntfsclone which
* stupidly used the volume version as the image version... )-: I hope NTFS
* never reaches version 10.0 and if it does one day I hope no-one is using
* such an old ntfsclone by then...
*
* NOTE: Only bump the minor version if the image format and header are still
* backwards compatible. Otherwise always bump the major version. If in
* doubt, bump the major version.
*/
#define NTFSCLONE_IMG_VER_MAJOR 10
#define NTFSCLONE_IMG_VER_MINOR 0
/* All values are in little endian. */
static struct {
char magic[IMAGE_MAGIC_SIZE];
u8 major_ver;
u8 minor_ver;
@ -165,8 +191,12 @@ struct {
s64 device_size;
s64 nr_clusters;
s64 inuse;
u32 offset_to_image_data; /* From start of image_hdr. */
} __attribute__((__packed__)) image_hdr;
#define NTFSCLONE_IMG_HEADER_SIZE_OLD \
(offsetof(typeof(image_hdr), offset_to_image_data))
#define NTFS_MBYTE (1000 * 1000)
#define ERR_PREFIX "ERROR"
@ -527,7 +557,7 @@ static void copy_cluster(int rescue, u64 rescue_lcn)
{
char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */
/* vol is NULL if opt.restore_image is set */
u32 csize = image_hdr.cluster_size;
u32 csize = le32_to_cpu(image_hdr.cluster_size);
void *fd = (void *)&fd_in;
off_t rescue_pos;
@ -589,10 +619,12 @@ static void lseek_to_cluster(s64 lcn)
static void image_skip_clusters(s64 count)
{
if (opt.save_image && count > 0) {
typeof(count) count_buf;
char buff[1 + sizeof(count)];
buff[0] = 0;
memcpy(buff + 1, &count, sizeof(count));
count_buf = cpu_to_sle64(count);
memcpy(buff + 1, &count_buf, sizeof(count_buf));
if (write_all(&fd_out, buff, sizeof(buff)) == -1)
perr_exit("write_all");
@ -629,13 +661,15 @@ static void clone_ntfs(u64 nr_clusters)
else
Printf("Cloning NTFS ...\n");
if ((buf = calloc(1, csize)) == NULL)
buf = ntfs_calloc(csize);
if (!buf)
perr_exit("clone_ntfs");
progress_init(&progress, p_counter, nr_clusters, 100);
if (opt.save_image) {
if (write_all(&fd_out, &image_hdr, sizeof(image_hdr)) == -1)
if (write_all(&fd_out, &image_hdr,
image_hdr.offset_to_image_data) == -1)
perr_exit("write_all");
}
@ -678,7 +712,7 @@ static void write_empty_clusters(s32 csize, s64 count,
static void restore_image(void)
{
s64 pos = 0, count;
s32 csize = image_hdr.cluster_size;
s32 csize = le32_to_cpu(image_hdr.cluster_size);
char cmd;
u64 p_counter = 0;
struct progress_bar progress;
@ -686,21 +720,25 @@ static void restore_image(void)
Printf("Restoring NTFS from image ...\n");
progress_init(&progress, p_counter, opt.std_out ?
image_hdr.nr_clusters : image_hdr.inuse, 100);
sle64_to_cpu(image_hdr.nr_clusters) :
sle64_to_cpu(image_hdr.inuse),
100);
while (pos < image_hdr.nr_clusters) {
while (pos < sle64_to_cpu(image_hdr.nr_clusters)) {
if (read_all(&fd_in, &cmd, sizeof(cmd)) == -1)
perr_exit("read_all");
if (cmd == 0) {
if (read_all(&fd_in, &count, sizeof(count)) == -1)
perr_exit("read_all");
if (!image_is_host_endian)
count = sle64_to_cpu(count);
if (opt.std_out)
write_empty_clusters(csize, count,
&progress, &p_counter);
else {
if (lseek(fd_out, count * csize, SEEK_CUR)
== (off_t)-1)
if (lseek(fd_out, count * csize, SEEK_CUR) ==
(off_t)-1)
perr_exit("restore_image: lseek");
}
pos += count;
@ -718,6 +756,7 @@ static void wipe_index_entry_timestams(INDEX_ENTRY *e)
static const struct timespec zero_time = { .tv_sec = 0, .tv_nsec = 0 };
s64 timestamp = timespec2ntfs(zero_time);
/* FIXME: can fall into infinite loop if corrupted */
while (!(e->ie_flags & INDEX_ENTRY_END)) {
e->key.file_name.creation_time = timestamp;
@ -744,7 +783,8 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr)
indexr = ntfs_index_root_get(ni, attr);
if (!indexr) {
ntfs_log_perror("Failed to read $INDEX_ROOT attribute");
perr_printf("Failed to read $INDEX_ROOT attribute of inode "
"%lld", ni->mft_no);
return;
}
@ -756,22 +796,25 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr)
byte = bitmap = ntfs_attr_readall(ni, AT_BITMAP, name, name_len, NULL);
if (!byte) {
ntfs_log_perror("Failed to read $BITMAP attribute");
perr_printf("Failed to read $BITMAP attribute");
goto out_indexr;
}
na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, name, name_len);
if (!na) {
ntfs_log_perror("Failed to open $INDEX_ALLOCATION attribute");
perr_printf("Failed to open $INDEX_ALLOCATION attribute");
goto out_bitmap;
}
tmp_indexa = indexa = malloc(na->data_size);
if (!tmp_indexa) {
ntfs_log_perror("malloc failed");
if (!na->data_size)
goto out_na;
}
tmp_indexa = indexa = ntfs_malloc(na->data_size);
if (!tmp_indexa)
goto out_na;
if (ntfs_attr_pread(na, 0, na->data_size, indexa) != na->data_size) {
ntfs_log_perror("Failed to read $INDEX_ALLOCATION attribute");
perr_printf("Failed to read $INDEX_ALLOCATION attribute");
goto out_indexa;
}
@ -779,8 +822,9 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr)
while ((u8 *)tmp_indexa < (u8 *)indexa + na->data_size) {
if (*byte & (1 << bit)) {
if (ntfs_mst_post_read_fixup((NTFS_RECORD *)tmp_indexa,
indexr->index_block_size)) {
ntfs_log_perror("Damaged INDX record");
le32_to_cpu(
indexr->index_block_size))) {
perr_printf("Damaged INDX record");
goto out_indexa;
}
entry = (INDEX_ENTRY *)((u8 *)tmp_indexa + le32_to_cpu(
@ -792,22 +836,22 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr)
perr_exit("ntfs_mft_usn_dec");
if (ntfs_mst_pre_write_fixup((NTFS_RECORD *)tmp_indexa,
indexr->index_block_size)) {
ntfs_log_perror("INDX write fixup failed");
le32_to_cpu(
indexr->index_block_size))) {
perr_printf("INDX write fixup failed");
goto out_indexa;
}
}
tmp_indexa = (INDEX_ALLOCATION *)((u8 *)tmp_indexa +
indexr->index_block_size);
le32_to_cpu(indexr->index_block_size));
bit++;
if (bit > 7) {
bit = 0;
byte++;
}
}
if (ntfs_rl_pwrite(vol, na->rl, 0, 0, na->data_size, indexa) != na->data_size)
ntfs_log_perror("ntfs_rl_pwrite failed");
perr_printf("ntfs_rl_pwrite failed for inode %lld", ni->mft_no);
out_indexa:
free(indexa);
out_na:
@ -847,7 +891,7 @@ static void wipe_index_root_timestamps(ATTR_RECORD *attr, s64 timestamp)
QUOTA_CONTROL_ENTRY *quota_q;
quota_q = (QUOTA_CONTROL_ENTRY *)((u8 *)entry +
entry->data_offset);
le16_to_cpu(entry->data_offset));
/*
* FIXME: no guarantee it's indeed /$Extend/$Quota:$Q.
* For now, as a minimal safeguard, we check only for
@ -866,7 +910,7 @@ static void wipe_index_root_timestamps(ATTR_RECORD *attr, s64 timestamp)
#define WIPE_TIMESTAMPS(atype, attr, timestamp) \
do { \
atype *ats; \
ats = (atype *)((char *)(attr) + (attr)->value_offset); \
ats = (atype *)((char *)(attr) + le16_to_cpu((attr)->value_offset)); \
\
ats->creation_time = (timestamp); \
ats->last_data_change_time = (timestamp); \
@ -1137,6 +1181,21 @@ static void mft_record_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni)
perr_exit("ntfs_mft_record_write");
}
static void mft_inode_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni)
{
s32 i;
mft_record_write_with_same_usn(volume, ni);
if (ni->nr_extents <= 0)
return;
for (i = 0; i < ni->nr_extents; ++i) {
ntfs_inode *eni = ni->extent_nis[i];
mft_record_write_with_same_usn(volume, eni);
}
}
static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk)
{
s64 inode = 0;
@ -1159,7 +1218,7 @@ static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk)
/* FIXME: Terrible kludge for libntfs not being able to return
a deleted MFT record as inode */
ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode));
ni = ntfs_calloc(sizeof(ntfs_inode));
if (!ni)
perr_exit("walk_clusters");
@ -1208,7 +1267,7 @@ static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk)
out:
if (wipe) {
wipe_unused_mft_data(ni);
mft_record_write_with_same_usn(volume, ni);
mft_inode_write_with_same_usn(volume, ni);
}
if (ntfs_inode_close(ni))
@ -1240,7 +1299,8 @@ static void setup_lcn_bitmap(void)
/* Determine lcn bitmap byte size and allocate it. */
lcn_bitmap.size = rounded_up_division(vol->nr_clusters, 8);
if (!(lcn_bitmap.bm = (unsigned char *)calloc(1, lcn_bitmap.size)))
lcn_bitmap.bm = ntfs_calloc(lcn_bitmap.size);
if (!lcn_bitmap.bm)
perr_exit("Failed to allocate internal buffer");
bitmap_file_data_fixup(vol->nr_clusters, &lcn_bitmap);
@ -1260,14 +1320,15 @@ static void print_volume_size(const char *str, s64 bytes)
}
static void print_disk_usage(u32 cluster_size, s64 nr_clusters, s64 inuse)
static void print_disk_usage(const char *spacer, u32 cluster_size,
s64 nr_clusters, s64 inuse)
{
s64 total, used;
total = nr_clusters * cluster_size;
used = inuse * cluster_size;
Printf("Space in use : %lld MB (%.1f%%) ",
Printf("Space in use %s: %lld MB (%.1f%%) ", spacer,
(long long)rounded_up_division(used, NTFS_MBYTE),
100.0 * ((float)used / total));
@ -1276,16 +1337,21 @@ static void print_disk_usage(u32 cluster_size, s64 nr_clusters, s64 inuse)
static void print_image_info(void)
{
Printf("NTFS volume version: %d.%d\n",
Printf("Ntfsclone image version: %d.%d\n",
image_hdr.major_ver, image_hdr.minor_ver);
Printf("Cluster size : %u bytes\n",
(unsigned int)image_hdr.cluster_size);
(unsigned)le32_to_cpu(image_hdr.cluster_size));
print_volume_size("Image volume size ",
image_hdr.nr_clusters * image_hdr.cluster_size);
Printf("Image device size : %lld bytes\n", image_hdr.device_size);
print_disk_usage(image_hdr.cluster_size,
image_hdr.nr_clusters,
image_hdr.inuse);
sle64_to_cpu(image_hdr.nr_clusters) *
le32_to_cpu(image_hdr.cluster_size));
Printf("Image device size : %lld bytes\n",
sle64_to_cpu(image_hdr.device_size));
print_disk_usage(" ", le32_to_cpu(image_hdr.cluster_size),
sle64_to_cpu(image_hdr.nr_clusters),
sle64_to_cpu(image_hdr.inuse));
Printf("Offset to image data : %u (0x%x) bytes\n",
(unsigned)le32_to_cpu(image_hdr.offset_to_image_data),
(unsigned)le32_to_cpu(image_hdr.offset_to_image_data));
}
static void check_if_mounted(const char *device, unsigned long new_mntflag)
@ -1348,7 +1414,7 @@ static void mount_volume(unsigned long new_mntflag)
volume_size(vol, vol->nr_clusters));
}
struct ntfs_walk_cluster backup_clusters = { NULL, NULL };
static struct ntfs_walk_cluster backup_clusters = { NULL, NULL };
static int device_offset_valid(int fd, s64 ofs)
{
@ -1475,14 +1541,61 @@ static s64 open_image(void)
if ((fd_in = open(opt.volume, O_RDONLY)) == -1)
perr_exit("failed to open image");
}
if (read_all(&fd_in, &image_hdr, sizeof(image_hdr)) == -1)
if (read_all(&fd_in, &image_hdr, NTFSCLONE_IMG_HEADER_SIZE_OLD) == -1)
perr_exit("read_all");
if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0)
err_exit("Input file is not an image! (invalid magic)\n");
if (image_hdr.major_ver < NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE) {
image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR;
image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR;
#if (__BYTE_ORDER == __BIG_ENDIAN)
Printf("Old image format detected. If the image was created "
"on a little endian architecture it will not "
"work. Use a more recent version of "
"ntfsclone to recreate the image.\n");
image_hdr.cluster_size = cpu_to_le32(image_hdr.cluster_size);
image_hdr.device_size = cpu_to_sle64(image_hdr.device_size);
image_hdr.nr_clusters = cpu_to_sle64(image_hdr.nr_clusters);
image_hdr.inuse = cpu_to_sle64(image_hdr.inuse);
#endif
image_hdr.offset_to_image_data =
const_cpu_to_le32((sizeof(image_hdr) + 7) & ~7);
image_is_host_endian = TRUE;
} else {
typeof(image_hdr.offset_to_image_data) offset_to_image_data;
int delta;
return image_hdr.device_size;
if (image_hdr.major_ver > NTFSCLONE_IMG_VER_MAJOR)
err_exit("Do not know how to handle image format "
"version %d.%d. Please obtain a "
"newer version of ntfsclone.\n",
image_hdr.major_ver,
image_hdr.minor_ver);
/* Read the image header data offset. */
if (read_all(&fd_in, &offset_to_image_data,
sizeof(offset_to_image_data)) == -1)
perr_exit("read_all");
image_hdr.offset_to_image_data =
le32_to_cpu(offset_to_image_data);
/*
* Read any fields from the header that we have not read yet so
* that the input stream is positioned correctly. This means
* we can support future minor versions that just extend the
* header in a backwards compatible way.
*/
delta = offset_to_image_data - (NTFSCLONE_IMG_HEADER_SIZE_OLD +
sizeof(image_hdr.offset_to_image_data));
if (delta > 0) {
char *dummy_buf;
dummy_buf = malloc(delta);
if (!dummy_buf)
perr_exit("malloc dummy_buffer");
if (read_all(&fd_in, dummy_buf, delta) == -1)
perr_exit("read_all");
}
}
return sle64_to_cpu(image_hdr.device_size);
}
static s64 open_volume(void)
@ -1508,12 +1621,14 @@ static s64 open_volume(void)
static void initialise_image_hdr(s64 device_size, s64 inuse)
{
memcpy(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE);
image_hdr.major_ver = vol->major_ver;
image_hdr.minor_ver = vol->minor_ver;
image_hdr.cluster_size = vol->cluster_size;
image_hdr.device_size = device_size;
image_hdr.nr_clusters = vol->nr_clusters;
image_hdr.inuse = inuse;
image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR;
image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR;
image_hdr.cluster_size = cpu_to_le32(vol->cluster_size);
image_hdr.device_size = cpu_to_sle64(device_size);
image_hdr.nr_clusters = cpu_to_sle64(vol->nr_clusters);
image_hdr.inuse = cpu_to_sle64(inuse);
image_hdr.offset_to_image_data = cpu_to_le32((sizeof(image_hdr) + 7) &
~7);
}
static void check_output_device(s64 input_size)
@ -1610,6 +1725,7 @@ static void check_dest_free_space(u64 src_bytes)
{
u64 dest_bytes;
struct statvfs stvfs;
struct stat st;
if (opt.metadata || opt.blkdev_out || opt.std_out)
return;
@ -1623,6 +1739,13 @@ static void check_dest_free_space(u64 src_bytes)
return;
}
/* If file is a FIFO then there is no point in checking the size. */
if (!fstat(fd_out, &st)) {
if (S_ISFIFO(st.st_mode))
return;
} else
Printf("WARNING: fstat failed: %s\n", strerror(errno));
dest_bytes = (u64)stvfs.f_frsize * stvfs.f_bfree;
if (!dest_bytes)
dest_bytes = (u64)stvfs.f_bsize * stvfs.f_bfree;
@ -1651,11 +1774,13 @@ int main(int argc, char **argv)
if (opt.restore_image) {
device_size = open_image();
ntfs_size = image_hdr.nr_clusters * image_hdr.cluster_size;
ntfs_size = sle64_to_cpu(image_hdr.nr_clusters) *
le32_to_cpu(image_hdr.cluster_size);
} else {
device_size = open_volume();
ntfs_size = vol->nr_clusters * vol->cluster_size;
}
// FIXME: This needs to be the cluster size...
ntfs_size += 512; /* add backup boot sector */
if (opt.std_out) {
@ -1671,7 +1796,7 @@ int main(int argc, char **argv)
flags |= O_EXCL;
}
if ((fd_out = open(opt.output, flags, S_IRWXU)) == -1)
if ((fd_out = open(opt.output, flags, S_IRUSR | S_IWUSR)) == -1)
perr_exit("Opening file '%s' failed", opt.output);
if (!opt.save_image)
@ -1691,7 +1816,7 @@ int main(int argc, char **argv)
walk_clusters(vol, &backup_clusters);
compare_bitmaps(&lcn_bitmap);
print_disk_usage(vol->cluster_size, vol->nr_clusters, image.inuse);
print_disk_usage("", vol->cluster_size, vol->nr_clusters, image.inuse);
check_dest_free_space(vol->cluster_size * image.inuse);

View File

@ -491,7 +491,8 @@ int main(int argc, char *argv[])
utils_set_locale();
vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force);
vol = utils_mount_volume(opts.device, MS_RDONLY |
(opts.force ? MS_RECOVER : 0));
if (!vol)
return 1;

View File

@ -56,7 +56,6 @@ struct match {
ATTR_TYPES type; /* Attribute type */
ntfschar *name; /* Attribute name */
int name_len; /* Length of attribute name */
u8 padding[4]; /* Unused: padding to 64 bit. */
};
#endif /* _NTFSCLUSTER_H_ */

View File

@ -1,10 +1,26 @@
/**
* ntfscmp - compare two NTFS volumes.
* ntfscmp - Part of the Linux-NTFS project.
*
* Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2007 Yura Pakhuchiy
*
* This utility is part of the Linux-NTFS project.
* This utility compare two NTFS volumes.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
@ -17,6 +33,10 @@
#include <errno.h>
#include <getopt.h>
#include <ntfs-3g/mst.h>
#include <ntfs-3g/support.h>
#include <ntfs-3g/misc.h>
#include "utils.h"
/* #include "version.h" */
@ -37,7 +57,7 @@ static const char *hibernated_volume_msg =
"turned off properly\n";
struct {
static struct {
int debug;
int show_progress;
int verbose;
@ -55,7 +75,6 @@ struct progress_bar {
int resolution;
int flags;
float unit;
u8 padding[4]; /* Unused: padding to 64 bit. */
};
/* WARNING: don't modify the text, external tools grep for it */
@ -308,7 +327,7 @@ static inline s64 get_nr_mft_records(ntfs_volume *vol)
#define NTFSCMP_EXTENSION_RECORD 4
#define NTFSCMP_INODE_CLOSE_ERROR 5
const char *ntfscmp_errs[] = {
static const char *ntfscmp_errs[] = {
"OK",
"INODE_OPEN_ERROR",
"INODE_OPEN_IO_ERROR",
@ -385,7 +404,8 @@ static void print_attribute_name(char *name)
}
#define GET_ATTR_NAME(a) \
((ntfschar *)(((u8 *)(a)) + ((a)->name_offset))), ((a)->name_length)
((ntfschar *)(((u8 *)(a)) + le16_to_cpu((a)->name_offset))), \
((a)->name_length)
static void free_name(char **name)
{
@ -464,6 +484,119 @@ static void print_ctx(ntfs_attr_search_ctx *ctx)
free_name(&name);
}
static void print_differ(ntfs_attr *na)
{
print_na(na);
printf("content: DIFFER\n");
}
static int cmp_buffer(u8 *buf1, u8 *buf2, long long int size, ntfs_attr *na)
{
if (memcmp(buf1, buf2, size)) {
print_differ(na);
return -1;
}
return 0;
}
struct cmp_ia {
INDEX_ALLOCATION *ia;
INDEX_ALLOCATION *tmp_ia;
u8 *bitmap;
u8 *byte;
s64 bm_size;
};
static int setup_cmp_ia(ntfs_attr *na, struct cmp_ia *cia)
{
cia->bitmap = ntfs_attr_readall(na->ni, AT_BITMAP, na->name,
na->name_len, &cia->bm_size);
if (!cia->bitmap) {
perr_println("Failed to readall BITMAP");
return -1;
}
cia->byte = cia->bitmap;
cia->tmp_ia = cia->ia = ntfs_malloc(na->data_size);
if (!cia->tmp_ia)
goto free_bm;
if (ntfs_attr_pread(na, 0, na->data_size, cia->ia) != na->data_size) {
perr_println("Failed to pread INDEX_ALLOCATION");
goto free_ia;
}
return 0;
free_ia:
free(cia->ia);
free_bm:
free(cia->bitmap);
return -1;
}
static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2)
{
struct cmp_ia cia1, cia2;
int bit, ret1, ret2;
u32 ib_size;
if (setup_cmp_ia(na1, &cia1))
return;
if (setup_cmp_ia(na2, &cia2))
return;
/*
* FIXME: ia can be the same even if the bitmap sizes are different.
*/
if (cia1.bm_size != cia1.bm_size)
goto out;
if (cmp_buffer(cia1.bitmap, cia2.bitmap, cia1.bm_size, na1))
goto out;
if (cmp_buffer((u8 *)cia1.ia, (u8 *)cia2.ia, 0x18, na1))
goto out;
ib_size = le32_to_cpu(cia1.ia->index.allocated_size) + 0x18;
bit = 0;
while ((u8 *)cia1.tmp_ia < (u8 *)cia1.ia + na1->data_size) {
if (*cia1.byte & (1 << bit)) {
ret1 = ntfs_mst_post_read_fixup((NTFS_RECORD *)
cia1.tmp_ia, ib_size);
ret2 = ntfs_mst_post_read_fixup((NTFS_RECORD *)
cia2.tmp_ia, ib_size);
if (ret1 != ret2) {
print_differ(na1);
goto out;
}
if (ret1 == -1)
continue;
if (cmp_buffer(((u8 *)cia1.tmp_ia) + 0x18,
((u8 *)cia2.tmp_ia) + 0x18,
le32_to_cpu(cia1.ia->
index.index_length), na1))
goto out;
}
cia1.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia1.tmp_ia + ib_size);
cia2.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia2.tmp_ia + ib_size);
bit++;
if (bit > 7) {
bit = 0;
cia1.byte++;
}
}
out:
free(cia1.ia);
free(cia2.ia);
free(cia1.bitmap);
free(cia2.bitmap);
return;
}
static void cmp_attribute_data(ntfs_attr *na1, ntfs_attr *na2)
{
s64 pos;
@ -503,15 +636,9 @@ static void cmp_attribute_data(ntfs_attr *na1, ntfs_attr *na2)
exit(1);
}
if (memcmp(buf1, buf2, count1)) {
print_na(na1);
printf("content");
if (opt.verbose)
printf(" (len = %lld)", count1);
printf(": DIFFER\n");
if (cmp_buffer(buf1, buf2, count1, na1))
return;
}
}
err_printf("%s read overrun: ", __FUNCTION__);
print_na(na1);
@ -531,7 +658,7 @@ static int cmp_attribute_header(ATTR_RECORD *a1, ATTR_RECORD *a2)
/*
* FIXME: includes paddings which are not handled by ntfsinfo!
*/
header_size = a1->length;
header_size = le32_to_cpu(a1->length);
}
return memcmp(a1, a2, header_size);
@ -575,6 +702,9 @@ static void cmp_attribute(ntfs_attr_search_ctx *ctx1,
return;
}
if (na1->type == AT_INDEX_ALLOCATION)
cmp_index_allocation(na1, na2);
else
cmp_attribute_data(na1, na2);
close_attribs:
@ -708,9 +838,11 @@ static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2)
old_atype1 = atype1;
old_ret1 = ret1;
if (!ret1 && (atype1 <= atype2 || ret2))
if (!ret1 && (le32_to_cpu(atype1) <= le32_to_cpu(atype2) ||
ret2))
ret1 = next_attr(ctx1, &atype1, &name1, &errno1);
if (!ret2 && (old_atype1 >= atype2 || old_ret1))
if (!ret2 && (le32_to_cpu(old_atype1) >= le32_to_cpu(atype2) ||
old_ret1))
ret2 = next_attr(ctx2, &atype2, &name2, &errno2);
print_attributes(ni1, atype1, atype2, name1, name2);
@ -724,14 +856,15 @@ static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2)
break;
}
if (ret2 || atype1 < atype2) {
if (ret2 || le32_to_cpu(atype1) < le32_to_cpu(atype2)) {
if (new_attribute(ctx1, prev_atype, prev_name)) {
print_ctx(ctx1);
printf("presence: EXISTS != MISSING\n");
set_prev(&prev_name, &prev_atype, name1, atype1);
set_prev(&prev_name, &prev_atype, name1,
atype1);
}
} else if (ret1 || atype1 > atype2) {
} else if (ret1 || le32_to_cpu(atype1) > le32_to_cpu(atype2)) {
if (new_attribute(ctx2, prev_atype, prev_name)) {
print_ctx(ctx2);
printf("presence: MISSING != EXISTS \n");

View File

@ -1,30 +1,20 @@
.\" Copyright (c) 2004\-2005 Yura Pakhuchiy.
.\" Copyright (c) 2004\-2007 Yura Pakhuchiy.
.\" Copyright (c) 2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSCP 8 "November 2005" "ntfs-3g @VERSION@"
.TH NTFSCP 8 "September 2007" "ntfs-3g @VERSION@"
.SH NAME
ntfscp \- overwrite file on an NTFS volume.
ntfscp \- copy file to an NTFS volume.
.SH SYNOPSIS
.B ntfscp
[\fIoptions\fR] \fIdevice source_file destination\fR
\fBntfscp\fR [\fIoptions\fR] \fIdevice source_file destination\fR
.SH DESCRIPTION
.B ntfscp
will overwrite file on an NTFS volume. At present
.B ntfscp
can't create new files.
.B destination
can be either file or directory. In case if
.B destination
is directory specified by name then
.B source_file
is copied into this directory, in case if
.B destination
is directory and specified by inode number then unnamed data attribute is
created for this inode and
.B source_file
is copied into it (WARNING: it's unusual to have unnamed data streams in the
directories, think twice before specifying directory by inode number).
\fBntfscp\fR will copy file to an NTFS volume. \fIdestination\fR can be either
file or directory. In case if \fIdestination\fR is directory specified by name
then \fIsource_file\fR is copied into this directory, in case if
\fIdestination\fR is directory and specified by inode number then unnamed data
attribute is created for this inode and \fIsource_file\fR is copied into it
(WARNING: it's unusual to have unnamed data streams in the directories, think
twice before specifying directory by inode number).
.SH OPTIONS
Below is a summary of all the options that
.B ntfscp
@ -96,24 +86,26 @@ windows is C):
.sp
.RE
.SH BUGS
There are no known problems with
.BR ntfscp .
If you find a bug please send an email describing the problem to the
development team:
There are no known problems with \fBntfscp\fR. 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 ntfscp
was written by Yura Pakhuchiy, with contributions from Anton Altaparmakov.
\fBntfscp\fR was written by Yura Pakhuchiy, with contributions from Anton
Altaparmakov and Hil Liao.
.SH DEDICATION
With love to Marina Sapego.
.SH AVAILABILITY
<<<<<<< HEAD
.B ntfscp
is part of the
.B ntfs-3g
package and is available from:
=======
\fBntfscp\fR is part of the \fBntfsprogs\fR package and is available from:
>>>>>>> linux-ntfs/libntfs-3g_port-v2_0_0
.br
.nh
http://www.tuxera.com/community/

View File

@ -1,10 +1,11 @@
/**
* ntfscp - Part of the Linux-NTFS project.
*
* Copyright (c) 2004-2005 Yura Pakhuchiy
* Copyright (c) 2004-2007 Yura Pakhuchiy
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2006 Hil Liao
*
* This utility will overwrite files on NTFS volume.
* This utility will copy file to an NTFS volume.
*
* 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
@ -43,6 +44,9 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
#endif
#include "types.h"
#include "attrib.h"
@ -68,7 +72,7 @@ struct options {
static const char *EXEC_NAME = "ntfscp";
static struct options opts;
volatile sig_atomic_t caught_terminate = 0;
static volatile sig_atomic_t caught_terminate = 0;
/**
* version - Print version information about the program
@ -79,9 +83,11 @@ volatile sig_atomic_t caught_terminate = 0;
*/
static void version(void)
{
ntfs_log_info("\n%s v%s (libntfs-3g) - Overwrite files on NTFS "
ntfs_log_info("\n%s v%s (libntfs-3g) - Copy file to an NTFS "
"volume.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c) 2004-2005 Yura Pakhuchiy\n");
ntfs_log_info("Copyright (c) 2004-2007 Yura Pakhuchiy\n");
ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n");
ntfs_log_info("Copyright (c) 2006 Hil Liao\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -178,7 +184,7 @@ static int parse_options(int argc, char **argv)
ntfs_log_error("Couldn't parse attribute.\n");
err++;
} else
opts.attribute = (ATTR_TYPES)attr;
opts.attribute = (ATTR_TYPES)cpu_to_le32(attr);
break;
case 'i':
opts.inode++;
@ -270,6 +276,34 @@ static void signal_handler(int arg __attribute__((unused)))
caught_terminate++;
}
/**
* Create a regular file under the given directory inode
*
* It is a wrapper function to ntfs_create(...)
*
* Return: the created file inode
*/
static ntfs_inode *ntfs_new_file(ntfs_inode *dir_ni,
const char *filename)
{
ntfschar *ufilename;
/* inode to the file that is being created */
ntfs_inode *ni;
int ufilename_len;
/* ntfs_mbstoucs(...) will allocate memory for ufilename if it's NULL */
ufilename = NULL;
ufilename_len = ntfs_mbstoucs_libntfscompat(filename, &ufilename, 0);
if (ufilename_len == -1) {
ntfs_log_perror("ERROR: Failed to convert '%s' to unicode",
filename);
return NULL;
}
ni = ntfs_create(dir_ni, 0, ufilename, ufilename_len, S_IFREG);
free(ufilename);
return ni;
}
/**
* main - Begin here
*
@ -313,14 +347,16 @@ int main(int argc, char *argv[])
if (opts.noaction)
flags = MS_RDONLY;
if (opts.force)
flags |= MS_RECOVER;
vol = utils_mount_volume(opts.device, flags, opts.force);
vol = utils_mount_volume(opts.device, flags);
if (!vol) {
ntfs_log_perror("ERROR: couldn't mount volume");
return 1;
}
if ((vol->flags & VOLUME_IS_DIRTY) && (!opts.force))
if ((vol->flags & VOLUME_IS_DIRTY) && !opts.force)
goto umount;
{
@ -352,45 +388,113 @@ int main(int argc, char *argv[])
} else
out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file);
if (!out) {
ntfs_log_perror("ERROR: Couldn't open destination file");
goto close_src;
}
if ((le16_to_cpu(out->mrec->flags) & MFT_RECORD_IS_DIRECTORY) &&
!opts.inode){
/*
* @out is directory and it was specified by pathname, add
* filename to path and reopen inode.
*/
char *filename, *new_dest_file;
/* Copy the file if the dest_file's parent dir can be opened. */
char *parent_dirname;
char *filename;
ntfs_inode *dir_ni;
ntfs_inode *ni;
int dest_path_len;
char *dirname_last_whack;
/*
* FIXME: There should exist more beautiful way to get filename.
* Not sure that it will work in windows, but I don't think that
* someone will use ntfscp under windows.
*/
filename = strrchr(opts.src_file, '/');
if (filename)
filename++;
else
filename = opts.src_file;
/* Add 2 bytes for '/' and null-terminator. */
new_dest_file = malloc(strlen(opts.dest_file) +
strlen(filename) + 2);
if (!new_dest_file) {
ntfs_log_perror("ERROR: malloc() failed");
goto close_dst;
}
strcpy(new_dest_file, opts.dest_file);
strcat(new_dest_file, "/");
strcat(new_dest_file, filename);
ntfs_inode_close(out);
out = ntfs_pathname_to_inode(vol, NULL, new_dest_file);
free(new_dest_file);
if (!out) {
ntfs_log_perror("ERROR: Failed to open destination "
"file");
filename = basename(opts.dest_file);
dest_path_len = strlen(opts.dest_file);
parent_dirname = strdup(opts.dest_file);
if (!parent_dirname) {
ntfs_log_perror("strdup() failed");
goto close_src;
}
dirname_last_whack = strrchr(parent_dirname, '/');
if (dirname_last_whack) {
dirname_last_whack[1] = 0;
dir_ni = ntfs_pathname_to_inode(vol, NULL,
parent_dirname);
} else {
ntfs_log_verbose("Target path does not contain '/'. "
"Using root directory as parent.\n");
dir_ni = ntfs_inode_open(vol, FILE_root);
}
if (dir_ni) {
if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
/* Remove the last '/' for estetic reasons. */
dirname_last_whack[0] = 0;
ntfs_log_error("The file '%s' already exists "
"and is not a directory. "
"Aborting.\n", parent_dirname);
free(parent_dirname);
ntfs_inode_close(dir_ni);
goto close_src;
}
ntfs_log_verbose("Creating a new file '%s' under '%s'"
"\n", filename, parent_dirname);
ni = ntfs_new_file(dir_ni, filename);
ntfs_inode_close(dir_ni);
if (!ni) {
ntfs_log_perror("Failed to create '%s' under "
"'%s'", filename,
parent_dirname);
free(parent_dirname);
goto close_src;
}
out = ni;
} else {
ntfs_log_perror("ERROR: Couldn't open '%s'",
parent_dirname);
free(parent_dirname);
goto close_src;
}
free(parent_dirname);
}
/* The destination is a directory. */
if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) {
char *filename;
char *overwrite_filename;
int overwrite_filename_len;
ntfs_inode *ni;
ntfs_inode *dir_ni;
int filename_len;
int dest_dirname_len;
filename = basename(opts.src_file);
dir_ni = out;
filename_len = strlen(filename);
dest_dirname_len = strlen(opts.dest_file);
overwrite_filename_len = filename_len+dest_dirname_len + 2;
overwrite_filename = malloc(overwrite_filename_len);
if (!overwrite_filename) {
ntfs_log_perror("ERROR: Failed to allocate %i bytes "
"memory for the overwrite filename",
overwrite_filename_len);
ntfs_inode_close(out);
goto close_src;
}
strcpy(overwrite_filename, opts.dest_file);
if (opts.dest_file[dest_dirname_len - 1] != '/') {
strcat(overwrite_filename, "/");
}
strcat(overwrite_filename, filename);
ni = ntfs_pathname_to_inode(vol, NULL, overwrite_filename);
/* Does a file with the same name exist in the dest dir? */
if (ni) {
ntfs_log_verbose("Destination path has a file with "
"the same name\nOverwriting the file "
"'%s'\n", overwrite_filename);
ntfs_inode_close(out);
out = ni;
} else {
ntfs_log_verbose("Creating a new file '%s' under "
"'%s'\n", filename, opts.dest_file);
ni = ntfs_new_file(dir_ni, filename);
ntfs_inode_close(dir_ni);
if (!ni) {
ntfs_log_perror("ERROR: Failed to create the "
"destination file under '%s'",
opts.dest_file);
free(overwrite_filename);
goto close_src;
}
out = ni;
}
free(overwrite_filename);
}
attr_name = ntfs_str2ucs(opts.attr_name, &attr_name_len);
@ -424,7 +528,7 @@ int main(int argc, char *argv[])
ntfs_log_verbose("Old file size: %lld\n", na->data_size);
if (na->data_size != new_size) {
if (ntfs_attr_truncate(na, new_size)) {
if (__ntfs_attr_truncate(na, new_size, FALSE)) {
ntfs_log_perror("ERROR: Couldn't resize attribute");
goto close_attr;
}

View File

@ -2,7 +2,8 @@
* ntfsdecrypt - Decrypt ntfs encrypted files. Part of the Linux-NTFS project.
*
* Copyright (c) 2005 Yuval Fledel
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2005-2007 Anton Altaparmakov
* Copyright (c) 2007 Yura Pakhuchiy
*
* This utility will decrypt files and print the decrypted data on the standard
* output.
@ -25,10 +26,6 @@
#include "config.h"
#if !defined(HAVE_GCRYPT_H) || !defined(HAVE_GNUTLS_PKCS12_H)
#error A required header file is missing. Aborting.
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@ -56,12 +53,8 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_GCRYPT_H
#include <gcrypt.h>
#endif
#ifdef HAVE_GNUTLS_PKCS12_H
#include <gnutls/pkcs12.h>
#endif
#include "types.h"
#include "attrib.h"
@ -74,6 +67,19 @@
typedef gcry_sexp_t ntfs_rsa_private_key;
#define NTFS_SHA1_THUMBPRINT_SIZE 0x14
#define NTFS_CRED_TYPE_CERT_THUMBPRINT const_cpu_to_le32(3)
#define NTFS_EFS_CERT_PURPOSE_OID_DDF "1.3.6.1.4.1.311.10.3.4"
#define NTFS_EFS_CERT_PURPOSE_OID_DRF "1.3.6.1.4.1.311.10.3.4.1"
typedef enum {
DF_TYPE_UNKNOWN,
DF_TYPE_DDF,
DF_TYPE_DRF,
} NTFS_DF_TYPES;
/**
* enum NTFS_CRYPTO_ALGORITHMS - List of crypto algorithms used by EFS (32 bit)
*
@ -101,14 +107,14 @@ typedef enum {
*/
typedef struct {
gcry_cipher_hd_t gcry_cipher_hd;
u32 alg_id;
le32 alg_id;
u8 *key_data;
gcry_cipher_hd_t *des_gcry_cipher_hd_ptr;
} ntfs_fek;
/* DESX-MS128 implementation for libgcrypt. */
static gcry_module_t ntfs_desx_module;
static unsigned ntfs_desx_algorithm_id = -1;
static int ntfs_desx_algorithm_id = -1;
typedef struct {
u64 in_whitening, out_whitening;
@ -446,19 +452,34 @@ static ntfs_rsa_private_key ntfs_rsa_private_key_import_from_gnutls(
return (ntfs_rsa_private_key)rsa_key;
}
/**
* ntfs_rsa_private_key_release
*/
static void ntfs_rsa_private_key_release(ntfs_rsa_private_key rsa_key)
{
gcry_sexp_release((gcry_sexp_t)rsa_key);
}
/**
* ntfs_pkcs12_extract_rsa_key
*/
static ntfs_rsa_private_key ntfs_pkcs12_extract_rsa_key(u8 *pfx, int pfx_size,
char *password)
char *password, char *thumbprint, int thumbprint_size,
NTFS_DF_TYPES *df_type)
{
int err, bag_index, flags;
gnutls_datum_t dpfx, dkey;
gnutls_pkcs12_t pkcs12;
gnutls_pkcs12_bag_t bag;
gnutls_x509_privkey_t pkey;
gnutls_pkcs12_t pkcs12 = NULL;
gnutls_pkcs12_bag_t bag = NULL;
gnutls_x509_privkey_t pkey = NULL;
gnutls_x509_crt_t crt = NULL;
ntfs_rsa_private_key rsa_key = NULL;
char purpose_oid[100];
size_t purpose_oid_size = sizeof(purpose_oid);
size_t tp_size = thumbprint_size;
BOOL have_thumbprint = FALSE;
*df_type = DF_TYPE_UNKNOWN;
/* Create a pkcs12 structure. */
err = gnutls_pkcs12_init(&pkcs12);
if (err) {
@ -474,7 +495,7 @@ static ntfs_rsa_private_key ntfs_pkcs12_extract_rsa_key(u8 *pfx, int pfx_size,
ntfs_log_error("Failed to convert the PFX file from DER to "
"native PKCS#12 format: %s\n",
gnutls_strerror(err));
goto out;
goto err;
}
/*
* Verify that the password is correct and that the key file has not
@ -491,9 +512,9 @@ retry_verify:
password = NULL;
goto retry_verify;
}
ntfs_log_error("Failed to verify the MAC (%s). Is the "
ntfs_log_error("Failed to verify the MAC: %s Is the "
"password correct?\n", gnutls_strerror(err));
goto out;
goto err;
}
for (bag_index = 0; ; bag_index++) {
err = gnutls_pkcs12_bag_init(&bag);
@ -501,29 +522,31 @@ retry_verify:
ntfs_log_error("Failed to initialize PKCS#12 Bag "
"structure: %s\n",
gnutls_strerror(err));
goto out;
goto err;
}
err = gnutls_pkcs12_get_bag(pkcs12, bag_index, bag);
if (err) {
if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
err = 0;
break;
}
ntfs_log_error("Failed to obtain Bag from PKCS#12 "
"structure: %s\n",
gnutls_strerror(err));
goto bag_out;
goto err;
}
check_again:
err = gnutls_pkcs12_bag_get_count(bag);
if (err < 0) {
ntfs_log_error("Failed to obtain Bag count: %s\n",
gnutls_strerror(err));
goto bag_out;
goto err;
}
err = gnutls_pkcs12_bag_get_type(bag, 0);
if (err < 0) {
ntfs_log_error("Failed to determine Bag type: %s\n",
gnutls_strerror(err));
goto bag_out;
goto err;
}
flags = 0;
switch (err) {
@ -534,14 +557,14 @@ check_again:
if (err < 0) {
ntfs_log_error("Failed to obtain Bag data: "
"%s\n", gnutls_strerror(err));
goto bag_out;
goto err;
}
err = gnutls_x509_privkey_init(&pkey);
if (err) {
ntfs_log_error("Failed to initialized "
"private key structure: %s\n",
gnutls_strerror(err));
goto bag_out;
goto err;
}
/* Decrypt the private key into GNU TLS format. */
err = gnutls_x509_privkey_import_pkcs8(pkey, &dkey,
@ -551,7 +574,7 @@ check_again:
"key from DER to GNU TLS "
"format: %s\n",
gnutls_strerror(err));
goto key_out;
goto err;
}
#if 0
/*
@ -579,38 +602,106 @@ check_again:
#endif
/* Convert the private key to our internal format. */
rsa_key = ntfs_rsa_private_key_import_from_gnutls(pkey);
goto key_out;
if (!rsa_key)
goto err;
break;
case GNUTLS_BAG_ENCRYPTED:
err = gnutls_pkcs12_bag_decrypt(bag, password);
if (err) {
ntfs_log_error("Failed to decrypt Bag: %s\n",
gnutls_strerror(err));
goto bag_out;
goto err;
}
goto check_again;
case GNUTLS_BAG_CERTIFICATE:
err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey);
if (err < 0) {
ntfs_log_error("Failed to obtain Bag data: "
"%s\n", gnutls_strerror(err));
goto err;
}
err = gnutls_x509_crt_init(&crt);
if (err) {
ntfs_log_error("Failed to initialize "
"certificate structure: %s\n",
gnutls_strerror(err));
goto err;
}
err = gnutls_x509_crt_import(crt, &dkey,
GNUTLS_X509_FMT_DER);
if (err) {
ntfs_log_error("Failed to convert certificate "
"from DER to GNU TLS format: "
"%s\n", gnutls_strerror(err));
goto err;
}
err = gnutls_x509_crt_get_key_purpose_oid(crt, 0,
purpose_oid, &purpose_oid_size, NULL);
if (err) {
ntfs_log_error("Failed to get key purpose "
"OID: %s\n",
gnutls_strerror(err));
goto err;
}
purpose_oid[purpose_oid_size - 1] = '\0';
if (!strcmp(purpose_oid,
NTFS_EFS_CERT_PURPOSE_OID_DRF))
*df_type = DF_TYPE_DRF;
else if (!strcmp(purpose_oid,
NTFS_EFS_CERT_PURPOSE_OID_DDF))
*df_type = DF_TYPE_DDF;
else {
ntfs_log_error("Certificate has unknown "
"purpose OID %s.\n",
purpose_oid);
err = EINVAL;
goto err;
}
/* Return the thumbprint to the caller. */
err = gnutls_x509_crt_get_fingerprint(crt,
GNUTLS_DIG_SHA1, thumbprint, &tp_size);
if (err) {
ntfs_log_error("Failed to get thumbprint: "
"%s\n", gnutls_strerror(err));
goto err;
}
if (tp_size != NTFS_SHA1_THUMBPRINT_SIZE) {
ntfs_log_error("Invalid thumbprint size %zd. "
"Should be %d.\n", tp_size,
thumbprint_size);
err = EINVAL;
goto err;
}
have_thumbprint = TRUE;
gnutls_x509_crt_deinit(crt);
crt = NULL;
break;
default:
/* We do not care about other types. */
break;
}
gnutls_pkcs12_bag_deinit(bag);
}
key_out:
err:
if (rsa_key && (err || *df_type == DF_TYPE_UNKNOWN ||
!have_thumbprint)) {
if (!err)
ntfs_log_error("Key type or thumbprint not found, "
"aborting.\n");
ntfs_rsa_private_key_release(rsa_key);
rsa_key = NULL;
}
if (crt)
gnutls_x509_crt_deinit(crt);
if (pkey)
gnutls_x509_privkey_deinit(pkey);
bag_out:
if (bag)
gnutls_pkcs12_bag_deinit(bag);
out:
if (pkcs12)
gnutls_pkcs12_deinit(pkcs12);
return rsa_key;
}
/**
* ntfs_rsa_private_key_release
*/
static void ntfs_rsa_private_key_release(ntfs_rsa_private_key rsa_key)
{
gcry_sexp_release((gcry_sexp_t)rsa_key);
}
/**
* ntfs_buffer_reverse -
*
@ -971,23 +1062,27 @@ static inline BOOL ntfs_des_test(void)
/**
* ntfs_fek_import_from_raw
*/
static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf,
unsigned fek_size __attribute__((unused)))
static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, unsigned fek_size)
{
ntfs_fek *fek;
u32 key_size, wanted_key_size, gcry_algo;
gcry_error_t err;
// TODO: Sanity checking of sizes and offsets.
key_size = le32_to_cpup(fek_buf);
//ntfs_log_debug("key_size 0x%x\n", key_size);
ntfs_log_debug("key_size 0x%x\n", key_size);
if (key_size + 16 > fek_size) {
ntfs_log_debug("Invalid FEK. It was probably decrypted with "
"the incorrect RSA key.");
errno = EINVAL;
return NULL;
}
fek = malloc(((((sizeof(*fek) + 7) & ~7) + key_size + 7) & ~7) +
sizeof(gcry_cipher_hd_t));
if (!fek) {
errno = ENOMEM;
return NULL;
}
fek->alg_id = *(u32*)(fek_buf + 8);
fek->alg_id = *(le32*)(fek_buf + 8);
//ntfs_log_debug("alg_id 0x%x\n", le32_to_cpu(fek->alg_id));
fek->key_data = (u8*)fek + ((sizeof(*fek) + 7) & ~7);
memcpy(fek->key_data, fek_buf + 16, key_size);
@ -1039,7 +1134,8 @@ static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf,
}
if (key_size != wanted_key_size) {
ntfs_log_error("%s key of %u bytes but needed size is %u "
"bytes, assuming corrupt key. Aborting.\n",
"bytes, assuming corrupt or incorrect key. "
"Aborting.\n",
gcry_cipher_algo_name(gcry_algo),
(unsigned)key_size, (unsigned)wanted_key_size);
err = EIO;
@ -1083,7 +1179,8 @@ static void ntfs_fek_release(ntfs_fek *fek)
* ntfs_df_array_fek_get
*/
static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array,
ntfs_rsa_private_key rsa_key)
ntfs_rsa_private_key rsa_key, char *thumbprint,
int thumbprint_size)
{
EFS_DF_HEADER *df_header;
EFS_DF_CREDENTIAL_HEADER *df_cred;
@ -1093,14 +1190,41 @@ static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array,
u32 df_count, fek_size;
unsigned i;
df_header = (EFS_DF_HEADER*)(df_array + 1);
df_count = le32_to_cpu(df_array->df_count);
for (i = 0; i < df_count; i++) {
if (!df_count)
ntfs_log_error("There are no elements in the DF array.\n");
df_header = (EFS_DF_HEADER*)(df_array + 1);
for (i = 0; i < df_count; i++, df_header = (EFS_DF_HEADER*)(
(u8*)df_header + le32_to_cpu(df_header->df_length))) {
df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)df_header +
le32_to_cpu(df_header->cred_header_offset));
if (df_cred->type != NTFS_CRED_TYPE_CERT_THUMBPRINT) {
ntfs_log_debug("Credential type is not certificate "
"thumbprint, skipping DF entry.\n");
continue;
}
df_cert = (EFS_DF_CERT_THUMBPRINT_HEADER*)((u8*)df_cred +
le32_to_cpu(
df_cred->cert_thumbprint_header_offset));
if (le32_to_cpu(df_cert->thumbprint_size) != thumbprint_size) {
ntfs_log_error("Thumbprint size %d is not valid "
"(should be %d), skipping this DF "
"entry.\n",
le32_to_cpu(df_cert->thumbprint_size),
thumbprint_size);
continue;
}
if (memcmp((u8*)df_cert +
le32_to_cpu(df_cert->thumbprint_offset),
thumbprint, thumbprint_size)) {
ntfs_log_debug("Thumbprints do not match, skipping "
"this DF entry.\n");
continue;
}
/*
* The thumbprints match so this is probably the DF entry
* matching the RSA key. Try to decrypt the FEK with it.
*/
fek_size = le32_to_cpu(df_header->fek_size);
fek_buf = (u8*)df_header + le32_to_cpu(df_header->fek_offset);
/* Decrypt the FEK. Note: This is done in place. */
@ -1115,8 +1239,6 @@ static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array,
} else
ntfs_log_error("Failed to decrypt the file "
"encryption key.\n");
df_header = (EFS_DF_HEADER*)((u8*)df_header +
le32_to_cpu(df_header->df_length));
}
return NULL;
}
@ -1125,10 +1247,11 @@ static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array,
* ntfs_inode_fek_get -
*/
static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode,
ntfs_rsa_private_key rsa_key)
ntfs_rsa_private_key rsa_key, char *thumbprint,
int thumbprint_size, NTFS_DF_TYPES df_type)
{
EFS_ATTR_HEADER *efs;
EFS_DF_ARRAY_HEADER *df_array;
EFS_DF_ARRAY_HEADER *df_array = NULL;
ntfs_fek *fek = NULL;
/* Obtain the $EFS contents. */
@ -1137,17 +1260,29 @@ static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode,
ntfs_log_perror("Failed to read $EFS attribute");
return NULL;
}
/* Iterate through the DDFs & DRFs until we obtain a key. */
if (efs->offset_to_ddf_array) {
/*
* Depending on whether the key is a normal key or a data recovery key,
* iterate through the DDF or DRF array, respectively.
*/
if (df_type == DF_TYPE_DDF) {
if (efs->offset_to_ddf_array)
df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs +
le32_to_cpu(efs->offset_to_ddf_array));
fek = ntfs_df_array_fek_get(df_array, rsa_key);
}
if (!fek && efs->offset_to_drf_array) {
else
ntfs_log_error("There are no entries in the DDF "
"array.\n");
} else if (df_type == DF_TYPE_DRF) {
if (efs->offset_to_drf_array)
df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs +
le32_to_cpu(efs->offset_to_drf_array));
fek = ntfs_df_array_fek_get(df_array, rsa_key);
}
else
ntfs_log_error("There are no entries in the DRF "
"array.\n");
} else
ntfs_log_error("Invalid DF type.\n");
if (df_array)
fek = ntfs_df_array_fek_get(df_array, rsa_key, thumbprint,
thumbprint_size);
free(efs);
return fek;
}
@ -1178,18 +1313,20 @@ static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset)
}
/* Apply the IV. */
if (fek->alg_id == CALG_AES_256) {
((u64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset);
((u64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset);
((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset);
((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset);
} else {
/* All other algos (Des, 3Des, DesX) use the same IV. */
((u64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset);
((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset);
}
return 512;
}
/**
* ntfs_cat_decrypt
* TODO:
* ntfs_cat_decrypt - Decrypt the contents of an encrypted file to stdout.
* @inode: An encrypted file's inode structure, as obtained by
* ntfs_inode_open().
* @fek: A file encryption key. As obtained by ntfs_inode_fek_get().
*/
static int ntfs_cat_decrypt(ntfs_inode *inode, ntfs_fek *fek)
{
@ -1272,6 +1409,8 @@ int main(int argc, char *argv[])
ntfs_fek *fek;
unsigned pfx_size;
int res;
NTFS_DF_TYPES df_type;
char thumbprint[NTFS_SHA1_THUMBPRINT_SIZE];
ntfs_log_set_handler(ntfs_log_handler_stderr);
@ -1300,19 +1439,20 @@ int main(int argc, char *argv[])
return 1;
}
/* Obtain the user's private RSA key from the key file. */
rsa_key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, password);
rsa_key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, password,
thumbprint, sizeof(thumbprint), &df_type);
/* Destroy the password. */
memset(password, 0, strlen(password));
/* No longer need the pfx file contents. */
free(pfx_buf);
if (!rsa_key) {
ntfs_log_error("Failed to extract the private RSA key. Did "
"you perhaps mistype the password?\n");
ntfs_log_error("Failed to extract the private RSA key.\n");
ntfs_crypto_deinit();
return 1;
}
/* Mount the ntfs volume. */
vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force);
vol = utils_mount_volume(opts.device, MS_RDONLY |
(opts.force ? MS_RECOVER : 0));
if (!vol) {
ntfs_log_error("Failed to mount ntfs volume. Aborting.\n");
ntfs_rsa_private_key_release(rsa_key);
@ -1332,7 +1472,8 @@ int main(int argc, char *argv[])
return 1;
}
/* Obtain the file encryption key of the encrypted file. */
fek = ntfs_inode_fek_get(inode, rsa_key);
fek = ntfs_inode_fek_get(inode, rsa_key, thumbprint,
sizeof(thumbprint), df_type);
ntfs_rsa_private_key_release(rsa_key);
if (fek) {
res = ntfs_cat_decrypt(inode, fek);

View File

@ -197,6 +197,9 @@ static int logfile_open(BOOL is_volume, const char *filename,
ntfs_inode *ni;
ntfs_attr *na;
/* Porting note: NTFS_MNT_FORENSIC is not needed when we mount
* the volume in read-only mode. No changes will be made to the
* logfile or anything else when we are in read only-mode. */
vol = ntfs_mount(filename, MS_RDONLY);
if (!vol)
log_err_exit(NULL, "Failed to mount %s: %s\n",

View File

@ -21,7 +21,7 @@ check for the first boot into Windows.
You may run
.B ntfsfix
on an NTFS volume if you think it was damaged by Windows or some other way
and it can't be mounted.
and it cannot be mounted.
.SH OPTIONS
Below is a summary of all the options that
.B ntfsfix

View File

@ -1,8 +1,9 @@
/**
* ntfsfix - Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2006 Anton Altaparmakov.
* Copyright (c) 2002-2006 Szabolcs Szakacsits.
* Copyright (c) 2000-2006 Anton Altaparmakov
* Copyright (c) 2002-2006 Szabolcs Szakacsits
* Copyright (c) 2007 Yura Pakhuchiy
*
* This utility fixes some common NTFS problems, resets the NTFS journal file
* and schedules an NTFS consistency check for the first boot into Windows.
@ -82,10 +83,8 @@ switch if you want to be able to build the NTFS utilities."
static const char *EXEC_NAME = "ntfsfix";
static const char *OK = "OK\n";
static const char *FAILED = "FAILED\n";
static BOOL vol_is_dirty = FALSE;
static BOOL journal_is_empty = FALSE;
struct {
static struct {
char *volume;
} opt;
@ -118,8 +117,9 @@ static void version(void)
{
ntfs_log_info("%s v%s\n\n"
"Attempt to fix an NTFS partition.\n\n"
"Copyright (c) 2000-2006 Anton Altaparmakov.\n"
"Copyright (c) 2002-2006 Szabolcs Szakacsits.\n\n",
"Copyright (c) 2000-2006 Anton Altaparmakov\n"
"Copyright (c) 2002-2006 Szabolcs Szakacsits\n"
"Copyright (c) 2007 Yura Pakhuchiy\n\n",
EXEC_NAME, VERSION);
ntfs_log_info("%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
exit(1);
@ -170,7 +170,7 @@ static void parse_options(int argc, char **argv)
/**
* OLD_ntfs_volume_set_flags
*/
static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags)
static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const le16 flags)
{
MFT_RECORD *m = NULL;
ATTR_RECORD *a;
@ -227,7 +227,7 @@ static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags)
goto err_out;
}
/* Set the volume flags. */
vol->flags = c->flags = cpu_to_le16(flags);
vol->flags = c->flags = flags;
if (ntfs_mft_record_write(vol, FILE_Volume, m)) {
ntfs_log_perror("Error writing $Volume");
goto err_out;
@ -245,56 +245,33 @@ err_exit:
*/
static int set_dirty_flag(ntfs_volume *vol)
{
u16 flags;
le16 flags;
if (vol_is_dirty == TRUE)
/* Porting note: We test for the current state of VOLUME_IS_DIRTY. This
* should actually be more appropriate than testing for NVolWasDirty. */
if (vol->flags | VOLUME_IS_DIRTY)
return 0;
ntfs_log_info("Setting required flags on partition... ");
/*
* Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
* and fix it for us.
*/
flags = vol->flags | VOLUME_IS_DIRTY;
/* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */
if (vol->major_ver >= 2)
flags |= VOLUME_MOUNTED_ON_NT4;
if (OLD_ntfs_volume_set_flags(vol, flags)) {
ntfs_log_info(FAILED);
ntfs_log_error("Error setting volume flags.\n");
return -1;
}
vol->flags = flags;
/* Porting note: libntfs-3g does not have the 'WasDirty' flag/property,
* and never touches the 'dirty' bit except when explicitly told to do
* so. Since we just wrote the VOLUME_IS_DIRTY bit to disk, and
* vol->flags is up-to-date, we can just ignore the NVolSetWasDirty
* statement. */
/* NVolSetWasDirty(vol); */
ntfs_log_info(OK);
vol_is_dirty = TRUE;
return 0;
}
/**
* set_dirty_flag_mount
*/
static int set_dirty_flag_mount(ntfs_volume *vol)
{
u16 flags;
if (vol_is_dirty == TRUE)
return 0;
ntfs_log_info("Setting required flags on partition... ");
/*
* Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
* and fix it for us.
*/
flags = vol->flags | VOLUME_IS_DIRTY;
/* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */
if (vol->major_ver >= 2)
flags |= VOLUME_MOUNTED_ON_NT4;
if (ntfs_volume_write_flags(vol, flags)) {
ntfs_log_info(FAILED);
ntfs_log_error("Error setting volume flags.\n");
return -1;
}
ntfs_log_info(OK);
vol_is_dirty = TRUE;
return 0;
}
@ -303,9 +280,8 @@ static int set_dirty_flag_mount(ntfs_volume *vol)
*/
static int empty_journal(ntfs_volume *vol)
{
if (journal_is_empty == TRUE)
if (NVolLogFileEmpty(vol))
return 0;
ntfs_log_info("Going to empty the journal ($LogFile)... ");
if (ntfs_logfile_reset(vol)) {
ntfs_log_info(FAILED);
@ -313,7 +289,6 @@ static int empty_journal(ntfs_volume *vol)
return -1;
}
ntfs_log_info(OK);
journal_is_empty = TRUE;
return 0;
}
@ -398,7 +373,7 @@ static int fix_mftmirr(ntfs_volume *vol)
use_mirr = FALSE;
mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
if (mrec->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_recordp(mrec)) {
if (ntfs_is_baad_record(mrec->magic)) {
ntfs_log_info(FAILED);
ntfs_log_error("$MFT error: Incomplete multi "
"sector transfer detected in "
@ -406,7 +381,7 @@ static int fix_mftmirr(ntfs_volume *vol)
")-:\n", s);
goto error_exit;
}
if (!ntfs_is_mft_recordp(mrec)) {
if (!ntfs_is_mft_record(mrec->magic)) {
ntfs_log_info(FAILED);
ntfs_log_error("$MFT error: Invalid mft "
"record for %s.\nCannot "
@ -416,14 +391,14 @@ static int fix_mftmirr(ntfs_volume *vol)
}
mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
if (mrec2->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_recordp(mrec2)) {
if (ntfs_is_baad_record(mrec2->magic)) {
ntfs_log_info(FAILED);
ntfs_log_error("$MFTMirr error: Incomplete "
"multi sector transfer "
"detected in %s.\n", s);
goto error_exit;
}
if (!ntfs_is_mft_recordp(mrec2)) {
if (!ntfs_is_mft_record(mrec2->magic)) {
ntfs_log_info(FAILED);
ntfs_log_error("$MFTMirr error: Invalid mft "
"record for %s.\n", s);
@ -431,7 +406,7 @@ static int fix_mftmirr(ntfs_volume *vol)
}
/* $MFT is corrupt but $MFTMirr is ok, use $MFTMirr. */
if (!(mrec->flags & MFT_RECORD_IN_USE) &&
!ntfs_is_mft_recordp(mrec))
!ntfs_is_mft_record(mrec->magic))
use_mirr = TRUE;
}
if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
@ -475,13 +450,13 @@ static int fix_mount(void)
ntfs_log_info("Attempting to correct errors... ");
dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops, NULL);
dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops,
NULL);
if (!dev) {
ntfs_log_info(FAILED);
ntfs_log_perror("Failed to allocate device");
return -1;
}
vol = ntfs_volume_startup(dev, 0);
if (!vol) {
ntfs_log_info(FAILED);
@ -490,17 +465,12 @@ static int fix_mount(void)
ntfs_device_free(dev);
return -1;
}
if (fix_mftmirr(vol) < 0)
goto error_exit;
/* FIXME: Will this fail? Probably... */
if (set_dirty_flag(vol) < 0)
goto error_exit;
if (empty_journal(vol) < 0)
goto error_exit;
ret = 0;
error_exit:
/* ntfs_umount() will invoke ntfs_device_free() for us. */
@ -550,6 +520,20 @@ int main(int argc, char **argv)
exit(1);
}
}
/* So the unmount does not clear it again. */
/* Porting note: The WasDirty flag was set here to prevent ntfs_unmount
* from clearing the dirty bit (which might have been set in
* fix_mount()). So the intention is to leave the dirty bit set.
*
* libntfs-3g does not automatically set or clear dirty flags on
* mount/unmount, this means that the assumption that the dirty flag is
* now set does not hold. So we need to set it if not already set. */
if(!(vol->flags & VOLUME_IS_DIRTY) && ntfs_volume_write_flags(vol,
vol->flags | VOLUME_IS_DIRTY)) {
ntfs_log_error("Error: Failed to set volume dirty flag (%d "
"(%s))!\n", errno, strerror(errno));
}
/* Check NTFS version is ok for us (in $Volume) */
ntfs_log_info("NTFS volume version is %i.%i.\n", vol->major_ver,
@ -558,22 +542,13 @@ int main(int argc, char **argv)
ntfs_log_error("Error: Unknown NTFS version.\n");
goto error_exit;
}
if (set_dirty_flag_mount(vol) < 0)
goto error_exit;
if (empty_journal(vol) < 0)
goto error_exit;
if (vol->major_ver >= 3) {
/* FIXME: If on NTFS 3.0+, check for presence of the usn journal and
disable it (if present) as Win2k might be unhappy otherwise and Bad
Things(TM) could happen depending on what applications are actually
using it for. */
/*
* FIXME: If on NTFS 3.0+, check for presence of the usn
* journal and stamp it if present.
*/
}
/* FIXME: Should we be marking the quota out of date, too? */
/* FIXME: We should be marking the quota out of date, too. */
/* That's all for now! */
ntfs_log_info("NTFS partition %s was processed successfully.\n",
vol->dev->d_name);

File diff suppressed because it is too large Load Diff

View File

@ -325,7 +325,7 @@ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label,
"allowed. Truncating excess characters.\n",
(unsigned)(0x100 / sizeof(ntfschar)));
label_len = 0x100;
new_label[label_len / sizeof(ntfschar)] = cpu_to_le16(L'\0');
new_label[label_len / sizeof(ntfschar)] = 0;
}
if (a) {
if (resize_resident_attribute_value(ctx->mrec, a, label_len)) {
@ -393,8 +393,9 @@ int main(int argc, char **argv)
if (!opts.label)
opts.noaction++;
vol = utils_mount_volume(opts.device, opts.noaction ? MS_RDONLY : 0,
opts.force);
vol = utils_mount_volume(opts.device,
(opts.noaction ? MS_RDONLY : 0) |
(opts.force ? MS_RECOVER : 0));
if (!vol)
return 1;

View File

@ -650,7 +650,8 @@ int main(int argc, char **argv)
utils_set_locale();
vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force);
vol = utils_mount_volume(opts.device, MS_RDONLY |
(opts.force ? MS_RECOVER : 0));
if (!vol) {
// FIXME: Print error... (AIA)
return 2;

View File

@ -745,7 +745,8 @@ static s64 move_datarun(ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec,
}
/**
* move_attribute
* move_attribute -
*
* > 0 Bytes moved / size to be moved
* = 0 Nothing to do
* < 0 Error
@ -790,7 +791,8 @@ static s64 move_attribute(ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec,
}
/**
* move_file
* move_file -
*
* > 0 Bytes moved / size to be moved
* = 0 Nothing to do
* < 0 Error
@ -873,8 +875,10 @@ int main(int argc, char *argv[])
if (opts.noaction)
flags |= MS_RDONLY;
if (opts.force)
flags |= MS_RECOVER;
vol = utils_mount_volume(opts.device, flags, opts.force);
vol = utils_mount_volume(opts.device, flags);
if (!vol) {
ntfs_log_info("!vol\n");
return 1;
@ -888,10 +892,19 @@ int main(int argc, char *argv[])
count = move_file(vol, inode, opts.location, 0);
if ((count > 0) && (!opts.nodirty)) {
if (ntfs_volume_write_flags(vol, vol->flags | VOLUME_IS_DIRTY) <
0) {
ntfs_log_error("Couldn't mark volume dirty\n");
/* Porting note: libntfs-3g does not automatically set or clear
* dirty flags on mount/unmount. It always preserves them until
* they are explicitly changed with ntfs_volume_write_flags.
* This means that the dirty flag is possibly not set, but
* should be set. So we explicitly set it with a call to
* ntfs_volume_write_flags. */
if(!(vol->flags & VOLUME_IS_DIRTY) && ntfs_volume_write_flags(
vol, vol->flags | VOLUME_IS_DIRTY)) {
ntfs_log_error("Error: Failed to set volume dirty "
"flag (%d (%s))!\n", errno, strerror(errno));
}
ntfs_log_info("Relocated %lld bytes\n", count);
}
if (count >= 0)

View File

@ -39,7 +39,6 @@ struct options {
int verbose; /* Extra output */
int noaction; /* Do not write to disk */
int nodirty; /* Do not mark volume dirty */
u8 padding[4]; /* Unused: alignment to 64 bit. */
};
#endif /* _NTFSMOVE_H_ */

View File

@ -1,9 +1,10 @@
.\" Copyright (c) 2002\-2005 Richard Russon.
.\" Copyright (c) 2002\-2003 Anton Altaparmakov.
.\" Copyright (c) 2005\-2006 Szabolcs Szakacsits.
.\" Copyright (c) 2005\-2007 Yura Pakhuchiy.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSPROGS 8 "April 2006" "ntfs-3g @VERSION@"
.TH NTFSPROGS 8 "September 2007" "ntfs-3g @VERSION@"
.SH NAME
ntfsprogs \- tools for doing neat things with NTFS
.SH OVERVIEW
@ -28,7 +29,7 @@ available for free and come with full source code.
\- Compare two NTFS filesystems and tell the differences.
.PP
.BR ntfscp (8)
\- Overwrite a file on an NTFS.
\- Copy a file to an NTFS volume.
.PP
.BR ntfsfix (8)
\- Check and fix some common errors, clear the LogFile and make Windows

View File

@ -4,6 +4,7 @@
* Copyright (c) 2002-2006 Szabolcs Szakacsits
* Copyright (c) 2002-2005 Anton Altaparmakov
* Copyright (c) 2002-2003 Richard Russon
* Copyright (c) 2007 Yura Pakhuchiy
*
* This utility will resize an NTFS volume without data loss.
*
@ -65,6 +66,7 @@
#include "runlist.h"
#include "utils.h"
/* #include "version.h" */
#include "misc.h"
static const char *EXEC_NAME = "ntfsresize";
@ -125,7 +127,7 @@ static const char *many_bad_sectors_msg =
"* other reason. We suggest to get a replacement disk as soon as possible. *\n"
"***************************************************************************\n";
struct {
static struct {
int verbose;
int debug;
int ro_flag;
@ -140,7 +142,6 @@ struct {
struct bitmap {
s64 size;
u8 *bm;
u8 padding[4]; /* Unused: padding to 64 bit. */
};
#define NTFS_PROGBAR 0x0001
@ -152,7 +153,6 @@ struct progress_bar {
int resolution;
int flags;
float unit;
u8 padding[4]; /* Unused: padding to 64 bit. */
};
struct llcn_t {
@ -202,7 +202,7 @@ typedef struct {
/* FIXME: This, lcn_bitmap and pos from find_free_cluster() will make a cluster
allocation related structure, attached to ntfs_resize_t */
s64 max_free_cluster_range = 0;
static s64 max_free_cluster_range = 0;
#define NTFS_MBYTE (1000 * 1000)
@ -349,7 +349,7 @@ static void proceed_question(void)
printf("Are you sure you want to proceed (y/[n])? ");
buf[0] = 0;
fgets(buf, sizeof(buf), stdin);
if (strchr(short_yes, buf[0]) == 0) {
if (!strchr(short_yes, buf[0])) {
printf("OK quitting. NO CHANGES have been made to your "
"NTFS volume.\n");
exit(1);
@ -369,6 +369,7 @@ static void version(void)
printf("Copyright (c) 2002-2006 Szabolcs Szakacsits\n");
printf("Copyright (c) 2002-2005 Anton Altaparmakov\n");
printf("Copyright (c) 2002-2003 Richard Russon\n");
printf("Copyright (c) 2007 Yura Pakhuchiy\n");
printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -803,11 +804,9 @@ static void build_lcn_usage_bitmap(ntfs_volume *vol, ntfsck_t *fsck)
lcn_length);
for (j = 0; j < lcn_length; j++) {
u64 k = (u64)lcn + j;
if (k >= (u64)vol->nr_clusters) {
long long outsiders = lcn_length - j;
fsck->outsider += outsiders;
@ -823,7 +822,7 @@ static void build_lcn_usage_bitmap(ntfs_volume *vol, ntfsck_t *fsck)
if (ntfs_bit_get_and_set(lcn_bitmap->bm, k, 1)) {
if (++fsck->multi_ref <= 10 || opt.verbose)
printf("Cluster %lld is referenced "
"multiply times!\n",
"multiple times!\n",
(long long)k);
continue;
}
@ -1173,7 +1172,7 @@ static void replace_attribute_runlist(ntfs_volume *vol,
ntfs_log_verbose("Bytes in use : %u\n", (unsigned int)
le32_to_cpu(ctx->mrec->bytes_in_use));
next_attr = (char *)a + le16_to_cpu(a->length);
next_attr = (char *)a + le32_to_cpu(a->length);
l = mp_size - l;
ntfs_log_verbose("Bytes in use new : %u\n", l + (unsigned int)
@ -1200,11 +1199,12 @@ static void replace_attribute_runlist(ntfs_volume *vol,
memmove(next_attr + l, next_attr, remains_size);
ctx->mrec->bytes_in_use = cpu_to_le32(l +
le32_to_cpu(ctx->mrec->bytes_in_use));
a->length += l;
a->length = cpu_to_le32(le32_to_cpu(a->length) + l);
}
if (!(mp = calloc(1, mp_size)))
perr_exit("Couldn't get memory");
mp = ntfs_calloc(mp_size);
if (!mp)
perr_exit("ntfsc_calloc couldn't get memory");
if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl, 0, NULL))
perr_exit("ntfs_mapping_pairs_build");
@ -1468,8 +1468,9 @@ static void rl_split_run(runlist **rl, int run, s64 pos)
size_head = run * sizeof(runlist_element);
size_tail = (items - run - 1) * sizeof(runlist_element);
if (!(rl_new = (runlist *)malloc(new_size)))
perr_exit("malloc");
rl_new = ntfs_malloc(new_size);
if (!rl_new)
perr_exit("ntfs_malloc");
rle_new = rl_new + run;
rle = *rl + run;
@ -1611,8 +1612,8 @@ static int is_mftdata(ntfs_resize_t *resize)
if (resize->mref == 0)
return 1;
if ( MREF(resize->mrec->base_mft_record) == 0 &&
MSEQNO(resize->mrec->base_mft_record) != 0)
if (MREF_LE(resize->mrec->base_mft_record) == 0 &&
MSEQNO_LE(resize->mrec->base_mft_record) != 0)
return 1;
return 0;
@ -1719,9 +1720,9 @@ static void relocate_inodes(ntfs_resize_t *resize)
progress_init(&resize->progress, 0, resize->relocations, resize->progress.flags);
resize->relocations = 0;
resize->mrec = (MFT_RECORD *)malloc(resize->vol->mft_record_size);
resize->mrec = ntfs_malloc(resize->vol->mft_record_size);
if (!resize->mrec)
perr_exit("malloc failed");
perr_exit("ntfs_malloc failed");
nr_mft_records = resize->vol->mft_na->initialized_size >>
resize->vol->mft_record_size_bits;
@ -1874,9 +1875,9 @@ static void truncate_badclust_bad_attr(ntfs_resize_t *resize)
rl_truncate(&rl_bad, nr_clusters);
a->highest_vcn = cpu_to_le64(nr_clusters - 1LL);
a->allocated_size = cpu_to_le64(nr_clusters * vol->cluster_size);
a->data_size = cpu_to_le64(nr_clusters * vol->cluster_size);
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);
replace_attribute_runlist(vol, resize->ctx, rl_bad);
@ -1951,10 +1952,10 @@ static void truncate_bitmap_data_attr(ntfs_resize_t *resize)
realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters);
}
a->highest_vcn = cpu_to_le64(nr_bm_clusters - 1LL);
a->allocated_size = cpu_to_le64(nr_bm_clusters * vol->cluster_size);
a->data_size = cpu_to_le64(bm_bsize);
a->initialized_size = cpu_to_le64(bm_bsize);
a->highest_vcn = cpu_to_sle64(nr_bm_clusters - 1LL);
a->allocated_size = cpu_to_sle64(nr_bm_clusters * vol->cluster_size);
a->data_size = cpu_to_sle64(bm_bsize);
a->initialized_size = cpu_to_sle64(bm_bsize);
replace_attribute_runlist(vol, resize->ctx, rl);
@ -2119,7 +2120,8 @@ static int setup_lcn_bitmap(struct bitmap *bm, s64 nr_clusters)
/* Determine lcn bitmap byte size and allocate it. */
bm->size = rounded_up_division(nr_clusters, 8);
if (!(bm->bm = (unsigned char *)calloc(1, bm->size)))
bm->bm = ntfs_calloc(bm->size);
if (!bm->bm)
return -1;
bitmap_file_data_fixup(nr_clusters, bm);
@ -2152,7 +2154,7 @@ static void update_bootsector(ntfs_resize_t *r)
r->progress.flags |= NTFS_PROGBAR_SUPPRESS;
copy_clusters(r, r->mftmir_rl.lcn, r->mftmir_old,
r->mftmir_rl.length);
bs.mftmirr_lcn = cpu_to_le64(r->mftmir_rl.lcn);
bs.mftmirr_lcn = cpu_to_sle64(r->mftmir_rl.lcn);
r->progress.flags &= ~NTFS_PROGBAR_SUPPRESS;
}
@ -2237,9 +2239,12 @@ static ntfs_volume *mount_volume(void)
err_exit("Device '%s' is mounted. "
"You must 'umount' it first.\n", opt.volume);
}
if (!(vol = ntfs_mount(opt.volume, opt.ro_flag /*| MS_NOATIME*/))) {
/*
* Pass NTFS_MNT_FORENSIC so that the mount process does not modify the
* volume at all. We will do the logfile emptying and dirty setting
* later if needed.
*/
if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_FORENSIC))) {
int err = errno;
perr_printf("Opening '%s' as NTFS failed", opt.volume);
@ -2286,31 +2291,26 @@ static ntfs_volume *mount_volume(void)
*/
static void prepare_volume_fixup(ntfs_volume *vol)
{
u16 flags;
printf("Schedule chkdsk for NTFS consistency check at Windows boot "
"time ...\n");
vol->flags |= VOLUME_IS_DIRTY;
if (ntfs_volume_write_flags(vol, vol->flags))
perr_exit("Failed to set the volume dirty");
flags = vol->flags | VOLUME_IS_DIRTY;
if (vol->major_ver >= 2)
flags |= VOLUME_MOUNTED_ON_NT4;
printf("Schedule chkdsk for NTFS consistency check at Windows "
"boot time ...\n");
if (ntfs_volume_write_flags(vol, flags))
perr_exit("Failed to set $Volume dirty");
/* Porting note: This flag does not exist in libntfs-3g. The dirty flag
* is never modified by libntfs-3g on unmount and we set it above. We
* can safely comment out this statement. */
/* NVolSetWasDirty(vol); */
if (vol->dev->d_ops->sync(vol->dev) == -1)
perr_exit("Failed to sync device");
printf("Resetting $LogFile ... (this might take a while)\n");
if (ntfs_logfile_reset(vol))
perr_exit("Failed to reset $LogFile");
if (vol->dev->d_ops->sync(vol->dev) == -1)
perr_exit("Failed to sync device");
}
static void set_disk_usage_constraint(ntfs_resize_t *resize)
{
/* last lcn for a filled up volume (no empty space) */
@ -2393,7 +2393,7 @@ int main(int argc, char **argv)
utils_set_locale();
if ((vol = mount_volume()) == NULL)
if (!(vol = mount_volume()))
err_exit("Couldn't open volume '%s'!\n", opt.volume);
device_size = ntfs_device_size_get(vol->dev, vol->sector_size);

View File

@ -715,7 +715,7 @@ int main(int argc, char **argv)
* Setup a default $AttrDef. FIXME: Should be reading this from the
* volume itself, at ntfs_mount() time.
*/
attr_defs = (ATTR_DEF*)&attrdef_ntfs12_array;
attr_defs = (ATTR_DEF*)&attrdef_ntfs3x_array;
/* Parse command line options. */
parse_options(argc, argv);
@ -807,4 +807,3 @@ int main(int argc, char **argv)
ntfs_log_quiet("ntfstruncate completed successfully. Have a nice day.\n");
return 0;
}

View File

@ -4,6 +4,7 @@
* Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2004-2005 Holger Ohmacht
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2007 Yura Pakhuchiy
*
* This utility will recover deleted files from an NTFS volume.
*
@ -221,10 +222,12 @@ static int parse_inode_arg(void)
*/
static void version(void)
{
ntfs_log_info("\n%s v%s (libntfs-3g) - Recover deleted files from an NTFS "
"Volume.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("\n%s v%s (libntfs-3g) - Recover deleted files from an "
"NTFS Volume.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c) 2002-2005 Richard Russon\n"
"Copyright (c) 2004-2005 Holger Ohmacht\n");
"Copyright (c) 2004-2005 Holger Ohmacht\n"
"Copyright (c) 2005 Anton Altaparmakov\n"
"Copyright (c) 2007 Yura Pakhuchiy\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -833,7 +836,8 @@ static void get_parent_name(struct filename* name, ntfs_volume* vol)
rec = calloc(1, vol->mft_record_size);
if (!rec) {
ntfs_log_error("ERROR: Couldn't allocate memory in get_parent_name()\n");
ntfs_log_error("ERROR: Couldn't allocate memory in "
"get_parent_name()\n");
return;
}
@ -841,10 +845,12 @@ static void get_parent_name(struct filename* name, ntfs_volume* vol)
if (!mft_data) {
ntfs_log_perror("ERROR: Couldn't open $MFT/$DATA");
} else {
inode_num = MREF(name->parent_mref);
inode_num = MREF_LE(name->parent_mref);
if (ntfs_attr_pread(mft_data, vol->mft_record_size * inode_num, vol->mft_record_size, rec) < 1) {
ntfs_log_error("ERROR: Couldn't read MFT Record %lld.\n", inode_num);
if (ntfs_attr_pread(mft_data, vol->mft_record_size * inode_num,
vol->mft_record_size, rec) < 1) {
ntfs_log_error("ERROR: Couldn't read MFT Record %lld"
".\n", inode_num);
} else if ((filename_attr = verify_parent(name, rec))) {
if (ntfs_ucstombs(filename_attr->file_name,
filename_attr->file_name_length,
@ -905,11 +911,13 @@ static int get_filenames(struct ufile *file, ntfs_volume* vol)
while ((rec = find_attribute(AT_FILE_NAME, ctx))) {
/* We know this will always be resident. */
attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset));
attr = (FILE_NAME_ATTR *)((char *)rec +
le16_to_cpu(rec->value_offset));
name = calloc(1, sizeof(*name));
if (!name) {
ntfs_log_error("ERROR: Couldn't allocate memory in get_filenames().\n");
ntfs_log_error("ERROR: Couldn't allocate memory in "
"get_filenames().\n");
count = -1;
break;
}
@ -989,28 +997,32 @@ static int get_data(struct ufile *file, ntfs_volume *vol)
while ((rec = find_attribute(AT_DATA, ctx))) {
data = calloc(1, sizeof(*data));
if (!data) {
ntfs_log_error("ERROR: Couldn't allocate memory in get_data().\n");
ntfs_log_error("ERROR: Couldn't allocate memory in "
"get_data().\n");
count = -1;
break;
}
data->resident = !rec->non_resident;
data->compressed = rec->flags & ATTR_IS_COMPRESSED;
data->encrypted = rec->flags & ATTR_IS_ENCRYPTED;
data->compressed = (rec->flags & ATTR_IS_COMPRESSED) ? 1 : 0;
data->encrypted = (rec->flags & ATTR_IS_ENCRYPTED) ? 1 : 0;
if (rec->name_length) {
data->uname = (ntfschar *) ((char *) rec + le16_to_cpu(rec->name_offset));
data->uname = (ntfschar *)((char *)rec +
le16_to_cpu(rec->name_offset));
data->uname_len = rec->name_length;
if (ntfs_ucstombs(data->uname, data->uname_len, &data->name,
0) < 0) {
ntfs_log_error("ERROR: Cannot translate name into current locale.\n");
if (ntfs_ucstombs(data->uname, data->uname_len,
&data->name, 0) < 0) {
ntfs_log_error("ERROR: Cannot translate name "
"into current locale.\n");
}
}
if (data->resident) {
data->size_data = le32_to_cpu(rec->value_length);
data->data = ((char*) (rec)) + le16_to_cpu(rec->value_offset);
data->data = (char*)rec +
le16_to_cpu(rec->value_offset);
} else {
data->size_alloc = sle64_to_cpu(rec->allocated_size);
data->size_data = sle64_to_cpu(rec->data_size);
@ -1168,17 +1180,20 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol)
clusters_free = 0;
if (data->encrypted) {
ntfs_log_verbose("File is encrypted, recovery is impossible.\n");
ntfs_log_verbose("File is encrypted, recovery is "
"impossible.\n");
continue;
}
if (data->compressed) {
ntfs_log_verbose("File is compressed, recovery not yet implemented.\n");
ntfs_log_verbose("File is compressed, recovery not yet "
"implemented.\n");
continue;
}
if (data->resident) {
ntfs_log_verbose("File is resident, therefore recoverable.\n");
ntfs_log_verbose("File is resident, therefore "
"recoverable.\n");
percent = 100;
data->percent = 100;
continue;
@ -1186,12 +1201,14 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol)
rl = data->runlist;
if (!rl) {
ntfs_log_verbose("File has no runlist, hence no data.\n");
ntfs_log_verbose("File has no runlist, hence no data."
"\n");
continue;
}
if (rl[0].length <= 0) {
ntfs_log_verbose("File has an empty runlist, hence no data.\n");
ntfs_log_verbose("File has an empty runlist, hence no "
"data.\n");
continue;
}
@ -1287,12 +1304,18 @@ static void dump_record(struct ufile *file)
ntfs_log_quiet("Filename: (%d) %s\n", f->name_space, f->name);
ntfs_log_quiet("File Flags: ");
if (f->flags & FILE_ATTR_SYSTEM) ntfs_log_quiet("System ");
if (f->flags & FILE_ATTR_DIRECTORY) ntfs_log_quiet("Directory ");
if (f->flags & FILE_ATTR_SPARSE_FILE) ntfs_log_quiet("Sparse ");
if (f->flags & FILE_ATTR_REPARSE_POINT) ntfs_log_quiet("Reparse ");
if (f->flags & FILE_ATTR_COMPRESSED) ntfs_log_quiet("Compressed ");
if (f->flags & FILE_ATTR_ENCRYPTED) ntfs_log_quiet("Encrypted ");
if (f->flags & FILE_ATTR_SYSTEM)
ntfs_log_quiet("System ");
if (f->flags & FILE_ATTR_DIRECTORY)
ntfs_log_quiet("Directory ");
if (f->flags & FILE_ATTR_SPARSE_FILE)
ntfs_log_quiet("Sparse ");
if (f->flags & FILE_ATTR_REPARSE_POINT)
ntfs_log_quiet("Reparse ");
if (f->flags & FILE_ATTR_COMPRESSED)
ntfs_log_quiet("Compressed ");
if (f->flags & FILE_ATTR_ENCRYPTED)
ntfs_log_quiet("Encrypted ");
if (!(f->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_DIRECTORY |
FILE_ATTR_SPARSE_FILE | FILE_ATTR_REPARSE_POINT |
FILE_ATTR_COMPRESSED | FILE_ATTR_ENCRYPTED))) {
@ -1309,13 +1332,17 @@ static void dump_record(struct ufile *file)
ntfs_log_quiet("Size alloc: %lld\n", f->size_alloc);
ntfs_log_quiet("Size data: %lld\n", f->size_data);
strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_c));
strftime(buffer, sizeof(buffer), "%F %R",
localtime(&f->date_c));
ntfs_log_quiet("Date C: %s\n", buffer);
strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_a));
strftime(buffer, sizeof(buffer), "%F %R",
localtime(&f->date_a));
ntfs_log_quiet("Date A: %s\n", buffer);
strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_m));
strftime(buffer, sizeof(buffer), "%F %R",
localtime(&f->date_m));
ntfs_log_quiet("Date M: %s\n", buffer);
strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_r));
strftime(buffer, sizeof(buffer), "%F %R",
localtime(&f->date_r));
ntfs_log_quiet("Date R: %s\n", buffer);
}
@ -1348,7 +1375,8 @@ static void dump_record(struct ufile *file)
}
}
ntfs_log_quiet("Amount potentially recoverable %d%%\n", d->percent);
ntfs_log_quiet("Amount potentially recoverable %d%%\n",
d->percent);
}
ntfs_log_quiet("________________________________________\n\n");
@ -1401,10 +1429,14 @@ static void list_record(struct ufile *file)
struct data *d = list_entry(item, struct data, list);
if (!d->name) {
if (d->resident) flagr = 'R';
else flagr = 'N';
if (d->compressed) flagc = 'C'; /* These two are mutually exclusive */
if (d->encrypted) flagc = 'E';
if (d->resident)
flagr = 'R';
else
flagr = 'N';
if (d->compressed)
flagc = 'C';
if (d->encrypted)
flagc = 'E';
percent = max(percent, d->percent);
}
@ -2122,7 +2154,8 @@ int main(int argc, char *argv[])
utils_set_locale();
vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force);
vol = utils_mount_volume(opts.device, MS_RDONLY |
(opts.force ? MS_RECOVER : 0));
if (!vol)
return 1;

View File

@ -2,6 +2,7 @@
* ntfsundelete - Part of the Linux-NTFS project.
*
* Copyright (c) 2002 Richard Russon
* Copyright (c) 2007 Yura Pakhuchiy
*
* This utility will recover deleted files from an NTFS volume.
*
@ -27,6 +28,7 @@
#include "types.h"
#include "list.h"
#include "runlist.h"
#include "utils.h"
enum optmode {
MODE_NONE = 0,
@ -57,7 +59,6 @@ struct options {
s64 mft_begin; /* Range for mft copy */
s64 mft_end;
char fillbyte; /* Use for unrecoverable sections */
char padding[7]; /* Unused: padding to 64 bit. */
};
struct filename {
@ -73,9 +74,8 @@ struct filename {
time_t date_r; /* read */
char *name; /* Filename in current locale */
FILE_NAME_TYPE_FLAGS name_space;
long long parent_mref;
leMFT_REF parent_mref;
char *parent_name;
char padding[7]; /* Unused: padding to 64 bit. */
};
struct data {
@ -93,7 +93,6 @@ struct data {
runlist_element *runlist; /* Decoded data runs */
int percent; /* Amount potentially recoverable */
void *data; /* If resident, a pointer to the data */
char padding[4]; /* Unused: padding to 64 bit. */
};
struct ufile {
@ -107,7 +106,6 @@ struct ufile {
int attr_list; /* MFT record may be one of many */
int directory; /* MFT record represents a directory */
MFT_RECORD *mft; /* Raw MFT record */
char padding[4]; /* Unused: padding to 64 bit. */
};
#endif /* _NTFSUNDELETE_H_ */

View File

@ -1340,12 +1340,14 @@ int main(int argc, char *argv[])
if (opts.info || opts.noaction)
flags = MS_RDONLY;
if (opts.force)
flags |= MS_RECOVER;
vol = utils_mount_volume(opts.device, flags, opts.force);
vol = utils_mount_volume(opts.device, flags);
if (!vol)
goto free;
if ((vol->flags & VOLUME_IS_DIRTY) && (!opts.force))
if ((vol->flags & VOLUME_IS_DIRTY) && !opts.force)
goto umount;
if (opts.info) {

View File

@ -3,25 +3,16 @@
#include "sd.h"
/**
* init_system_file_sd
* init_system_file_sd -
*
* NTFS 1.2, 3.0, 3.1 - System files security decriptors
* NTFS 3.1 - System files security decriptors
* =====================================================
*
* Create the security descriptor for system file number @sys_file_no and
* return a pointer to the descriptor.
*
* $MFT, $MFTMirr, $LogFile, $AttrDef, $Bitmap, $Boot, $BadClus, and $UpCase
* are the same.
*
* $Volume, $Quota, and system files 0xb-0xf are the same. They are almost the
* same as the above, the only difference being that the two SIDs present in
* the DACL grant GENERIC_WRITE and GENERIC_READ equivalent privileges while
* the above only grant GENERIC_READ equivalent privileges. (For some reason
* the flags for GENERIC_READ/GENERIC_WRITE are not set by NT4, even though
* the permissions are equivalent, so we comply.
*
* Root directory system file (".") is different altogether.
* Note the root directory system file (".") is very different and handled by a
* different function.
*
* The sd is returned in *@sd_val and has length *@sd_val_len.
*
@ -46,15 +37,9 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len)
sd->revision = 1;
sd->alignment = 0;
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
if (sys_file_no == FILE_root) {
*sd_val_len = 0x50;
sd->owner = const_cpu_to_le32(0x30);
sd->group = const_cpu_to_le32(0x40);
} else {
*sd_val_len = 0x68;
*sd_val_len = 0x64;
sd->owner = const_cpu_to_le32(0x48);
sd->group = const_cpu_to_le32(0x58);
}
sd->group = const_cpu_to_le32(0x54);
sd->sacl = const_cpu_to_le32(0);
sd->dacl = const_cpu_to_le32(0x14);
/*
@ -64,13 +49,8 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len)
acl = (ACL*)((char*)sd + le32_to_cpu(sd->dacl));
acl->revision = 2;
acl->alignment1 = 0;
if (sys_file_no == FILE_root) {
acl->size = const_cpu_to_le16(0x1c);
acl->ace_count = const_cpu_to_le16(1);
} else {
acl->size = const_cpu_to_le16(0x34);
acl->ace_count = const_cpu_to_le16(2);
}
acl->alignment2 = const_cpu_to_le16(0);
/*
* Now at offset 0x1c, just after the DACL's ACL, we have the first
@ -78,31 +58,20 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len)
*/
aa_ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL));
aa_ace->type = ACCESS_ALLOWED_ACE_TYPE;
if (sys_file_no == FILE_root)
aa_ace->flags = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
else
aa_ace->flags = 0;
aa_ace->size = const_cpu_to_le16(0x14);
switch (sys_file_no) {
case FILE_MFT: case FILE_MFTMirr: case FILE_LogFile:
case FILE_AttrDef: case FILE_Bitmap: case FILE_Boot:
case FILE_BadClus: case FILE_UpCase:
case FILE_AttrDef:
case FILE_Boot:
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ |
FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA;
break;
case FILE_Volume: case FILE_Secure: case 0xb ... 0xffff:
default:
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_WRITE |
FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
FILE_WRITE_EA | FILE_READ_EA | FILE_APPEND_DATA |
FILE_WRITE_DATA | FILE_READ_DATA;
break;
case FILE_root:
aa_ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
FILE_READ_ATTRIBUTES | FILE_DELETE_CHILD |
FILE_TRAVERSE | FILE_WRITE_EA | FILE_READ_EA |
FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE |
FILE_LIST_DIRECTORY;
break;
}
aa_ace->sid.revision = 1;
aa_ace->sid.sub_authority_count = 1;
@ -111,41 +80,30 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len)
aa_ace->sid.identifier_authority.value[2] = 0;
aa_ace->sid.identifier_authority.value[3] = 0;
aa_ace->sid.identifier_authority.value[4] = 0;
if (sys_file_no == FILE_root) {
/* SECURITY_WORLD_SID_AUTHORITY (S-1-1) */
aa_ace->sid.identifier_authority.value[5] = 1;
aa_ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_WORLD_RID);
/* This is S-1-1-0, the WORLD_SID. */
} else {
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
aa_ace->sid.identifier_authority.value[5] = 5;
aa_ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
}
/*
* Now at offset 0x30 within security descriptor, just after the first
* ACE of the DACL. All system files, except the root directory, have
* a second ACE.
*/
if (sys_file_no != FILE_root) {
/* The second ACE of the DACL. Type is access allowed. */
aa_ace = (ACCESS_ALLOWED_ACE*)((char*)aa_ace +
le16_to_cpu(aa_ace->size));
aa_ace->type = ACCESS_ALLOWED_ACE_TYPE;
aa_ace->flags = 0;
aa_ace->size = const_cpu_to_le16(0x18);
/* Only $AttrDef and $Boot behave differently to everything else. */
switch (sys_file_no) {
case FILE_MFT: case FILE_MFTMirr:
case FILE_LogFile: case FILE_AttrDef:
case FILE_Bitmap: case FILE_Boot:
case FILE_BadClus: case FILE_UpCase:
case FILE_AttrDef:
case FILE_Boot:
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ |
FILE_READ_ATTRIBUTES | FILE_READ_EA |
FILE_READ_DATA;
break;
case FILE_Volume: case FILE_Secure:
case 0xb ... 0xffff :
default:
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ |
FILE_WRITE_ATTRIBUTES |
FILE_READ_ATTRIBUTES | FILE_WRITE_EA |
@ -166,12 +124,13 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len)
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
aa_ace->sid.sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
/* Now at offset 0x48 into the security descriptor. */
}
/* As specified in the security descriptor, we now have the owner SID.*/
/*
* Now at offset 0x48 into the security descriptor, as specified in the
* security descriptor, we now have the owner SID.
*/
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
sid->revision = 1;
sid->sub_authority_count = 2;
sid->sub_authority_count = 1;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
@ -179,12 +138,10 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len)
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
/*
* Now at offset 0x40 or 0x58 (root directory and the other system
* files, respectively) into the security descriptor, as specified in
* the security descriptor, we have the group SID.
* Now at offset 0x54 into the security descriptor, as specified in the
* security descriptor, we have the group SID.
*/
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
sid->revision = 1;
@ -201,56 +158,53 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len)
}
/**
* init_root_sd_31 (ERSO)
* creates the security_descriptor for the root folder on ntfs 3.1.
* It is very long; lots of ACE's at first, then large pieces of zeroes;
* the owner user/group is near the end. On a partition created with
* w2k3 the owner user/group at the end is surrounded by 'garbage', which I
* yet do not understand. Here I have replaced the 'garbage' with
* zeros, which seems to work. Chkdsk does not add the 'garbage', nor alter
* this security descriptor in any way.
* init_root_sd -
*
* Creates the security_descriptor for the root folder on ntfs 3.1 as created
* by Windows Vista (when the format is done from the disk management MMC
* snap-in, note this is different from the format done from the disk
* properties in Windows Explorer).
*/
void init_root_sd_31(u8 **sd_val, int *sd_val_len)
void init_root_sd(u8 **sd_val, int *sd_val_len)
{
SECURITY_DESCRIPTOR_RELATIVE *sd;
ACL *acl;
ACCESS_ALLOWED_ACE *ace;
SID *sid;
static char sd_array[0x1030];
*sd_val_len = 0x1030;
static char sd_array[0x102c];
*sd_val_len = 0x102c;
*sd_val = (u8*)&sd_array;
//security descriptor relative
sd = (SECURITY_DESCRIPTOR_RELATIVE*)sd_array;
sd->revision = 0x01;
sd->alignment = 0x00;
sd->revision = SECURITY_DESCRIPTOR_REVISION;
sd->alignment = 0;
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
sd->owner = const_cpu_to_le32(0x1014);
sd->group = const_cpu_to_le32(0x1024);
sd->sacl = const_cpu_to_le32(0x00);
sd->dacl = const_cpu_to_le32(0x14);
sd->group = const_cpu_to_le32(0x1020);
sd->sacl = 0;
sd->dacl = const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE));
//acl
acl = (ACL*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
acl->revision = 0x02;
acl->alignment1 = 0x00;
acl->revision = ACL_REVISION;
acl->alignment1 = 0;
acl->size = const_cpu_to_le16(0x1000);
acl->ace_count = const_cpu_to_le16(0x07);
acl->alignment2 = const_cpu_to_le16(0x00);
acl->ace_count = const_cpu_to_le16(0x08);
acl->alignment2 = 0;
//ace1
ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
ace->type = 0x00;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = 0;
ace->size = const_cpu_to_le16(0x18);
ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_WRITE_DATA |
FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA |
FILE_TRAVERSE | FILE_DELETE_CHILD |
FILE_READ_ATTRIBUTES;
ace->sid.revision = 0x01;
ace->sid.revision = SID_REVISION;
ace->sid.sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
@ -261,21 +215,17 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len)
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//ace2
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
ace->size = const_cpu_to_le16(0x14);
ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_WRITE_DATA |
FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA |
FILE_TRAVERSE | FILE_DELETE_CHILD |
FILE_READ_ATTRIBUTES;
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x01;
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
INHERIT_ONLY_ACE;
ace->size = const_cpu_to_le16(0x18);
ace->mask = GENERIC_ALL;
ace->sid.revision = SID_REVISION;
ace->sid.sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
@ -284,35 +234,40 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len)
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//ace3
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
INHERIT_ONLY_ACE;
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = 0;
ace->size = const_cpu_to_le16(0x14);
ace->mask = const_cpu_to_le32(0x10000000);
ace->sid.revision = 0x01;
ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_WRITE_DATA |
FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA |
FILE_TRAVERSE | FILE_DELETE_CHILD |
FILE_READ_ATTRIBUTES;
ace->sid.revision = SID_REVISION;
ace->sid.sub_authority_count = 0x01;
/* SECURITY_CREATOR_SID_AUTHORITY (S-1-3) */
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 3;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_CREATOR_OWNER_RID);
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
//ace4
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
ace->size = const_cpu_to_le16(0x18);
ace->mask = const_cpu_to_le32(0x1200A9);
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x02;
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
INHERIT_ONLY_ACE;
ace->size = const_cpu_to_le16(0x14);
ace->mask = GENERIC_ALL;
ace->sid.revision = SID_REVISION;
ace->sid.sub_authority_count = 0x01;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
@ -321,18 +276,20 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len)
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS);
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
//ace5
ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = CONTAINER_INHERIT_ACE;
ace->size = const_cpu_to_le16(0x18);
ace->mask = const_cpu_to_le32(0x04);
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x02;
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = 0;
ace->size = const_cpu_to_le16(0x14);
ace->mask = SYNCHRONIZE | READ_CONTROL | DELETE |
FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
FILE_TRAVERSE | FILE_WRITE_EA | FILE_READ_EA |
FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE |
FILE_LIST_DIRECTORY;
ace->sid.revision = SID_REVISION;
ace->sid.sub_authority_count = 0x01;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
@ -341,18 +298,17 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len)
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS);
const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID);
//ace6
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
ace->size = const_cpu_to_le16(0x18);
ace->mask = const_cpu_to_le32(0x02);
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x02;
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
INHERIT_ONLY_ACE;
ace->size = const_cpu_to_le16(0x14);
ace->mask = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE;
ace->sid.revision = SID_REVISION;
ace->sid.sub_authority_count = 0x01;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
@ -361,32 +317,52 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len)
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS);
const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID);
//ace7
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = 0x00;
ace->size = const_cpu_to_le16(0x14);
ace->mask = const_cpu_to_le32(0x1200A9);
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x01;
/* SECURITY_WORLD_SID_AUTHORITY (S-1-1) */
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = 0;
ace->size = const_cpu_to_le16(0x18);
ace->mask = SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
FILE_TRAVERSE | FILE_READ_EA | FILE_LIST_DIRECTORY;
ace->sid.revision = SID_REVISION;
ace->sid.sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 1;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_WORLD_RID);
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS);
//ace8
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
INHERIT_ONLY_ACE;
ace->size = const_cpu_to_le16(0x18);
ace->mask = GENERIC_READ | GENERIC_EXECUTE;
ace->sid.revision = SID_REVISION;
ace->sid.sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS);
//owner sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
sid->revision = 0x01;
sid->sub_authority_count = 0x02;
sid->sub_authority_count = 0x01;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
@ -394,10 +370,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len)
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
//group sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
@ -410,419 +383,18 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len)
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
}
/**
* init_secure
*
* NTFS 3.0 - System files security decriptors
* ===========================================
* Create the security descriptor entries in $SDS data stream like they
* are in a partition, newly formatted with windows 2000
*/
void init_secure_30(char *sd_val)
{
SECURITY_DESCRIPTOR_HEADER *sds;
SECURITY_DESCRIPTOR_RELATIVE *sd;
ACL *acl;
ACCESS_ALLOWED_ACE *ace;
SID *sid;
/*
* security descriptor #1
*/
//header
sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val);
sds->hash = const_cpu_to_le32(0xF80312F0);
sds->security_id = const_cpu_to_le32(0x0100);
sds->offset = const_cpu_to_le64(0x00);
sds->length = const_cpu_to_le32(0x7C);
//security descriptor relative
sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds +
sizeof(SECURITY_DESCRIPTOR_HEADER));
sd->revision = 0x01;
sd->alignment = 0x00;
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
sd->owner = const_cpu_to_le32(0x48);
sd->group = const_cpu_to_le32(0x58);
sd->sacl = const_cpu_to_le32(0x00);
sd->dacl = const_cpu_to_le32(0x14);
//acl
acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
acl->revision = 0x02;
acl->alignment1 = 0x00;
acl->size = const_cpu_to_le16(0x34);
acl->ace_count = const_cpu_to_le16(0x02);
acl->alignment2 = 0x00;
//ace1
ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL));
ace->type = 0x00;
ace->flags = 0x00;
ace->size = const_cpu_to_le16(0x14);
ace->mask = const_cpu_to_le32(0x120089);
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x01;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
//ace2
ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = 0x00;
ace->size = const_cpu_to_le16(0x18);
ace->mask = const_cpu_to_le32(0x120089);
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//owner sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
sid->revision = 0x01;
sid->sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
sid->identifier_authority.value[2] = 0;
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//group sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
sid->revision = 0x01;
sid->sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
sid->identifier_authority.value[2] = 0;
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
/*
* security descriptor #2
*/
//header
sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80);
sds->hash = const_cpu_to_le32(0xB32451);
sds->security_id = const_cpu_to_le32(0x0101);
sds->offset = const_cpu_to_le64(0x80);
sds->length = const_cpu_to_le32(0x7C);
//security descriptor relative
sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds +
sizeof(SECURITY_DESCRIPTOR_HEADER));
sd->revision = 0x01;
sd->alignment = 0x00;
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
sd->owner = const_cpu_to_le32(0x48);
sd->group = const_cpu_to_le32(0x58);
sd->sacl = const_cpu_to_le32(0x00);
sd->dacl = const_cpu_to_le32(0x14);
//acl
acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
acl->revision = 0x02;
acl->alignment1 = 0x00;
acl->size = const_cpu_to_le16(0x34);
acl->ace_count = const_cpu_to_le16(0x02);
acl->alignment2 = 0x00;
//ace1
ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL));
ace->type = 0x00;
ace->flags = 0x00;
ace->size = const_cpu_to_le16(0x14);
ace->mask = const_cpu_to_le32(0x12019F);
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x01;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
//ace2
ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = 0x00;
ace->size = const_cpu_to_le16(0x18);
ace->mask = const_cpu_to_le32(0x12019F);
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//owner sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
sid->revision = 0x01;
sid->sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
sid->identifier_authority.value[2] = 0;
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//group sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
sid->revision = 0x01;
sid->sub_authority_count = 0x02;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
sid->identifier_authority.value[2] = 0;
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
/*
* security descriptor #3
*/
//header
sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80 + 0x80);
sds->hash = const_cpu_to_le32(0x0A9F9562);
sds->security_id = const_cpu_to_le32(0x0102);
sds->offset = const_cpu_to_le64(0x0100);
sds->length = const_cpu_to_le32(0x60);
//security descriptor relative
sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds +
sizeof(SECURITY_DESCRIPTOR_HEADER));
sd->revision = 0x01;
sd->alignment = 0x00;
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
sd->owner = const_cpu_to_le32(0x30);
sd->group = const_cpu_to_le32(0x40);
sd->sacl = const_cpu_to_le32(0x00);
sd->dacl = const_cpu_to_le32(0x14);
//acl
acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
acl->revision = 0x02;
acl->alignment1 = 0x00;
acl->size = const_cpu_to_le16(0x1C);
acl->ace_count = const_cpu_to_le16(0x01);
acl->alignment2 = 0x00;
//ace1
ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL));
ace->type = 0x00;
ace->flags = 0x00;
ace->size = const_cpu_to_le16(0x14);
ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_WRITE_DATA |
FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA |
FILE_TRAVERSE | FILE_DELETE_CHILD |
FILE_READ_ATTRIBUTES;
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x01;
// SECURITY_NT_SID_AUTHORITY (S-1-5)
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
//owner sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
sid->revision = 0x01;
sid->sub_authority_count = 0x02;
// SECURITY_NT_SID_AUTHORITY (S-1-5)
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
sid->identifier_authority.value[2] = 0;
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//group sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
sid->revision = 0x01;
sid->sub_authority_count = 0x01;
// SECURITY_NT_SID_AUTHORITY (S-1-5)
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
sid->identifier_authority.value[2] = 0;
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
/*
* security descriptor #4
*/
//header
sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80 + 0x80 + 0x60);
sds->hash = const_cpu_to_le32(0x453F0A2E);
sds->security_id = const_cpu_to_le32(0x0103);
sds->offset = const_cpu_to_le64(0x0160);
sds->length = const_cpu_to_le32(0x78);
//security descriptor relative
sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds +
sizeof(SECURITY_DESCRIPTOR_HEADER));
sd->revision = 0x01;
sd->alignment = 0x00;
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
sd->owner = const_cpu_to_le32(0x48);
sd->group = const_cpu_to_le32(0x58);
sd->sacl = const_cpu_to_le32(0x00);
sd->dacl = const_cpu_to_le32(0x14);
//acl
acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
acl->revision = 0x02;
acl->alignment1 = 0x00;
acl->size = const_cpu_to_le16(0x34);
acl->ace_count = const_cpu_to_le16(0x02);
acl->alignment2 = 0x00;
//ace1
ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL));
ace->type = 0x00;
ace->flags = 0x00;
ace->size = const_cpu_to_le16(0x18);
ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_WRITE_DATA |
FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA |
FILE_TRAVERSE | FILE_DELETE_CHILD |
FILE_READ_ATTRIBUTES;
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x02;
// SECURITY_NT_SID_AUTHORITY (S-1-5)
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
ace->sid.sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//ace2
ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size));
ace->type = 0x00;
ace->flags = 0x00;
ace->size = const_cpu_to_le16(0x14);
ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_WRITE_DATA |
FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA |
FILE_TRAVERSE | FILE_DELETE_CHILD |
FILE_READ_ATTRIBUTES;
ace->sid.revision = 0x01;
ace->sid.sub_authority_count = 0x01;
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
ace->sid.identifier_authority.value[0] = 0;
ace->sid.identifier_authority.value[1] = 0;
ace->sid.identifier_authority.value[2] = 0;
ace->sid.identifier_authority.value[3] = 0;
ace->sid.identifier_authority.value[4] = 0;
ace->sid.identifier_authority.value[5] = 5;
ace->sid.sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
//owner sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
sid->revision = 0x01;
sid->sub_authority_count = 0x02;
// SECURITY_NT_SID_AUTHORITY (S-1-5)
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
sid->identifier_authority.value[2] = 0;
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] =
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
//group sid
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
sid->revision = 0x01;
sid->sub_authority_count = 0x01;
// SECURITY_NT_SID_AUTHORITY (S-1-5)
sid->identifier_authority.value[0] = 0;
sid->identifier_authority.value[1] = 0;
sid->identifier_authority.value[2] = 0;
sid->identifier_authority.value[3] = 0;
sid->identifier_authority.value[4] = 0;
sid->identifier_authority.value[5] = 5;
sid->sub_authority[0] =
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
return;
}
/**
* init_secure_31(char **r, int size);
* init_secure_sds -
*
* NTFS 3.1 - System files security decriptors
* ===========================================
* Create the security descriptor entries in $SDS data stream like they
* are in a partition, newly formatted with windows 2003
*/
void init_secure_31(char *sd_val)
void init_secure_sds(char *sd_val)
{
SECURITY_DESCRIPTOR_HEADER *sds;
SECURITY_DESCRIPTOR_RELATIVE *sd;

View File

@ -4,9 +4,8 @@
#include "types.h"
void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len);
void init_root_sd_31(u8 **sd_val, int *sd_val_len);
void init_secure_30(char *sd_val);
void init_secure_31(char *sd_val);
void init_root_sd(u8 **sd_val, int *sd_val_len);
void init_secure_sds(char *sd_val);
#endif /* _NTFS_SD_H_ */

View File

@ -1,90 +0,0 @@
/**
* upcase - Part of the Linux-NTFS project.
*
* Copyright (c) 2001 Richard Russon
* Copyright (c) 2001-2006 Anton Altaparmakov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS source
* in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "endians.h"
#include "types.h"
#include "upcase.h"
/**
* init_upcase_table
*/
void init_upcase_table(ntfschar *uc, u32 uc_len)
{
static int uc_run_table[][3] = { /* Start, End, Add */
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
{0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128},
{0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112},
{0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126},
{0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8},
{0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8},
{0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8},
{0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7},
{0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16},
{0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26},
{0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32},
{0}
};
static int uc_dup_table[][2] = { /* Start, End */
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
{0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9},
{0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95},
{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
{0}
};
static int uc_byte_table[][2] = { /* Offset, Value */
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
{0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F},
{0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9},
{0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE},
{0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7},
{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
{0}
};
int i, r;
memset(uc, 0, uc_len);
uc_len >>= 1;
/* Generate the little endian Unicode upcase table used by ntfs. */
for (i = 0; (u32)i < uc_len; i++)
uc[i] = cpu_to_le16(i);
for (r = 0; uc_run_table[r][0]; r++)
for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
uc[i] = cpu_to_le16(le16_to_cpu(uc[i]) +
uc_run_table[r][2]);
for (r = 0; uc_dup_table[r][0]; r++)
for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1);
for (r = 0; uc_byte_table[r][0]; r++)
uc[uc_byte_table[r][0]] = cpu_to_le16(uc_byte_table[r][1]);
}

View File

@ -1,7 +0,0 @@
#ifndef _NTFS_UPCASE_H_
#define _NTFS_UPCASE_H_
void init_upcase_table(ntfschar *uc, u32 uc_len);
#endif /* _NTFS_UPCASE_H_ */

View File

@ -4,6 +4,7 @@
* Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2003-2006 Anton Altaparmakov
* Copyright (c) 2003 Lode Leroy
* Copyright (c) 2005-2007 Yura Pakhuchiy
*
* A set of shared functions for ntfs utilities
*
@ -71,6 +72,7 @@
#include "dir.h"
/* #include "version.h" */
#include "logging.h"
#include "misc.h"
const char *ntfs_bugs = "Developers' email address: "NTFS_DEV_LIST"\n";
const char *ntfs_home = "Linux NTFS homepage: http://www.linux-ntfs.org\n";
@ -81,6 +83,50 @@ const char *ntfs_gpl = "This program is free software, released under the GNU "
"\"COPYING\" distributed with this program, or online at:\n"
"http://www.gnu.org/copyleft/gpl.html\n";
static const char *invalid_ntfs_msg =
"The device '%s' doesn't have a valid NTFS.\n"
"Maybe you selected the wrong device? Or the whole disk instead of a\n"
"partition (e.g. /dev/hda, not /dev/hda1)? Or the other way around?\n";
static const char *corrupt_volume_msg =
"NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n"
"The usage of the /f parameter is very IMPORTANT! No modification was\n"
"made to NTFS by this software.\n";
static const char *hibernated_volume_msg =
"The NTFS partition is hibernated. Please resume Windows and turned it \n"
"off properly, so mounting could be done safely.\n";
static const char *unclean_journal_msg =
"Access is denied because the NTFS journal file is unclean. Choices are:\n"
" A) Shutdown Windows properly.\n"
" B) Click the 'Safely Remove Hardware' icon in the Windows taskbar\n"
" notification area before disconnecting the device.\n"
" C) Use 'Eject' from Windows Explorer to safely remove the device.\n"
" D) If you ran chkdsk previously then boot Windows again which will\n"
" automatically initialize the journal.\n"
" E) Submit 'force' option (WARNING: This solution it not recommended).\n"
" F) ntfsmount: Mount the volume read-only by using the 'ro' mount option.\n";
static const char *opened_volume_msg =
"Access is denied because the NTFS volume is already exclusively opened.\n"
"The volume may be already mounted, or another software may use it which\n"
"could be identified for example by the help of the 'fuser' command.\n";
static const char *dirty_volume_msg =
"Volume is scheduled for check.\n"
"Please boot into Windows TWICE, or use the 'force' option.\n"
"NOTE: If you had not scheduled check and last time accessed this volume\n"
"using ntfsmount and shutdown system properly, then init scripts in your\n"
"distribution are broken. Please report to your distribution developers\n"
"(NOT to us!) that init scripts kill ntfsmount or mount.ntfs-fuse during\n"
"shutdown instead of proper umount.\n";
static const char *fakeraid_msg =
"You seem to have a SoftRAID/FakeRAID hardware and must use an activated,\n"
"different device under /dev/mapper, (e.g. /dev/mapper/nvidia_eahaabcc1)\n"
"to mount NTFS. Please see the 'dmraid' documentation for help.\n";
/**
* utils_set_locale
*/
@ -91,16 +137,16 @@ int utils_set_locale(void)
locale = setlocale(LC_ALL, "");
if (!locale) {
locale = setlocale(LC_ALL, NULL);
ntfs_log_error("Failed to set locale, using default '%s'.\n", locale);
ntfs_log_error("Failed to set locale, using default '%s'.\n",
locale);
return 1;
} else {
return 0;
}
}
#ifndef NTFS_RICH
/**
* utils_valid_device - Perform some safety checks on the device, before we start
* utils_valid_device - Perform some safety checks on the device, before start
* @name: Full pathname of the device/file to work with
* @force: Continue regardless of problems
*
@ -116,7 +162,7 @@ int utils_valid_device(const char *name, int force)
struct stat st;
#ifdef __CYGWIN32__
/* FIXME: This doesn't work for Cygwin, so just return success for now... */
/* FIXME: This doesn't work for Cygwin, so just return success. */
return 1;
#endif
if (!name) {
@ -125,37 +171,30 @@ int utils_valid_device(const char *name, int force)
}
if (stat(name, &st) == -1) {
if (errno == ENOENT) {
if (errno == ENOENT)
ntfs_log_error("The device %s doesn't exist\n", name);
} else {
ntfs_log_perror("Error getting information about %s", name);
}
else
ntfs_log_perror("Error getting information about %s",
name);
return 0;
}
if (!S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode)) {
ntfs_log_warning("%s is not a block device, "
"nor regular file.\n", name);
if (!force) {
ntfs_log_error("Use the force option to work with other"
" file types, for your own risk!\n");
return 0;
}
ntfs_log_warning("Forced to continue.\n");
}
/* Make sure the file system is not mounted. */
if (ntfs_check_if_mounted(name, &mnt_flags)) {
ntfs_log_perror("Failed to determine whether %s is mounted", name);
ntfs_log_perror("Failed to determine whether %s is mounted",
name);
if (!force) {
ntfs_log_error("Use the force option to ignore this error.\n");
ntfs_log_error("Use the force option to ignore this "
"error.\n");
return 0;
}
ntfs_log_warning("Forced to continue.\n");
} else if (mnt_flags & NTFS_MF_MOUNTED) {
ntfs_log_warning("The device %s, is mounted.\n", name);
if (!force) {
ntfs_log_error("Use the force option to work a mounted filesystem.\n");
ntfs_log_error("%s", opened_volume_msg);
ntfs_log_error("You can use force option to avoid this "
"check, but this is not recommended\n"
"and may lead to data corruption.\n");
return 0;
}
ntfs_log_warning("Forced to continue.\n");
@ -167,7 +206,7 @@ int utils_valid_device(const char *name, int force)
/**
* utils_mount_volume - Mount an NTFS volume
*/
ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force)
ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags)
{
ntfs_volume *vol;
@ -176,42 +215,58 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL f
return NULL;
}
if (!utils_valid_device(device, force))
/* Porting notes:
*
* libntfs-3g does not have the 'force' flag in ntfs_mount_flags.
* The 'force' flag in libntfs bypasses two safety checks when mounting
* read/write:
* 1. Do not mount when the VOLUME_IS_DIRTY flag in
* VOLUME_INFORMATION is set.
* 2. Do not mount when the logfile is unclean.
*
* libntfs-3g only has safety check number 2. The dirty flag is simply
* ignored because we are confident that we can handle a dirty volume.
* So we treat MS_RECOVER like NTFS_MNT_FORCE, knowing that the first
* check is always bypassed.
*/
if (!utils_valid_device(device, flags & MS_RECOVER))
return NULL;
vol = ntfs_mount(device, flags);
if (!vol) {
int err;
err = errno;
ntfs_log_perror("Couldn't mount device '%s'", device);
if (err == EPERM)
ntfs_log_error("Windows was hibernated. Try to mount "
"volume in windows, shut down and try "
"again.\n");
if (err == EOPNOTSUPP)
ntfs_log_error("Windows did not shut down properly. "
"Try to mount volume in windows, "
"shut down and try again.\n");
ntfs_log_perror("Failed to mount '%s'", device);
if (errno == EINVAL)
ntfs_log_error(invalid_ntfs_msg, device);
else if (errno == EIO)
ntfs_log_error("%s", corrupt_volume_msg);
else if (errno == EPERM)
ntfs_log_error("%s", hibernated_volume_msg);
else if (errno == EOPNOTSUPP)
ntfs_log_error("%s", unclean_journal_msg);
else if (errno == EBUSY)
ntfs_log_error("%s", opened_volume_msg);
else if (errno == ENXIO)
ntfs_log_error("%s", fakeraid_msg);
return NULL;
}
/* Porting notes:
* libntfs-3g does not record whether the volume log file was dirty
* before mount, so we can only warn if the VOLUME_IS_DIRTY flag is set
* in VOLUME_INFORMATION. */
if (vol->flags & VOLUME_IS_DIRTY) {
ntfs_log_warning("Volume is dirty.\n");
if (!force) {
ntfs_log_error("Run chkdsk and try again, or use the "
"force option.\n");
if (!(flags & MS_RECOVER)) {
ntfs_log_error("%s", dirty_volume_msg);
ntfs_umount(vol, FALSE);
return NULL;
}
ntfs_log_warning("Forced to continue.\n");
ntfs_log_error("WARNING: Dirty volume mount was forced by the "
"'force' mount option.\n");
}
return vol;
}
#endif
/**
* utils_parse_size - Convert a string representing a size
* @value: String to be parsed
@ -333,7 +388,6 @@ int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale)
return 1;
}
#ifndef NTFS_RICH
/**
* find_attribute - Find an attribute of the given type
* @type: An attribute type, e.g. AT_FILE_NAME
@ -403,7 +457,6 @@ ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft)
return rec;
}
#endif
/**
* utils_inode_get_name
*
@ -414,11 +467,12 @@ ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft)
* if parent is 5 (/) stop
* get inode of parent
*/
#define max_path 20
int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize)
{
// XXX option: names = posix/win32 or dos
// flags: path, filename, or both
const int max_path = 20;
ntfs_volume *vol;
ntfs_attr_search_ctx *ctx;
@ -426,7 +480,7 @@ int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize)
FILE_NAME_ATTR *attr;
int name_space;
MFT_REF parent = FILE_root;
char *names[max_path + 1];// XXX malloc? and make max bigger?
char *names[max_path + 1];// XXX ntfs_malloc? and make max bigger?
int i, len, offset = 0;
if (!inode || !buffer) {
@ -470,7 +524,7 @@ int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize)
&names[i], 0) < 0) {
char *temp;
ntfs_log_error("Couldn't translate filename to current locale.\n");
temp = malloc(30);
temp = ntfs_malloc(30);
if (!temp)
return 0;
snprintf(temp, 30, "<MFT%llu>", (unsigned
@ -528,6 +582,7 @@ int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize)
return 1;
}
#undef max_path
/**
* utils_attr_get_name
@ -549,7 +604,8 @@ int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int b
name = NULL;
namelen = ntfs_ucsnlen(attrdef->name, sizeof(attrdef->name));
if (ntfs_ucstombs(attrdef->name, namelen, &name, 0) < 0) {
ntfs_log_error("Couldn't translate attribute type to current locale.\n");
ntfs_log_error("Couldn't translate attribute type to "
"current locale.\n");
// <UNKNOWN>?
return 0;
}
@ -573,9 +629,10 @@ int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int b
name = NULL;
namelen = attr->name_length;
if (ntfs_ucstombs((ntfschar *)((char *)attr + attr->name_offset),
namelen, &name, 0) < 0) {
ntfs_log_error("Couldn't translate attribute name to current locale.\n");
if (ntfs_ucstombs((ntfschar *)((char *)attr + le16_to_cpu(
attr->name_offset)), namelen, &name, 0) < 0) {
ntfs_log_error("Couldn't translate attribute name to current "
"locale.\n");
// <UNKNOWN>?
len = snprintf(buffer, bufsize, "<UNKNOWN>");
return 0;
@ -603,7 +660,10 @@ int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int b
*
* This function has a static buffer in which it caches a section of $Bitmap.
* If the lcn, being tested, lies outside the range, the buffer will be
* refreshed.
* refreshed. @bmplcn stores offset to the first bit (in bits) stored in the
* buffer.
*
* NOTE: Be very carefull with shifts by 3 everywhere in this function.
*
* Return: 1 Cluster is in use
* 0 Cluster is free space
@ -612,8 +672,7 @@ int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int b
int utils_cluster_in_use(ntfs_volume *vol, long long lcn)
{
static unsigned char buffer[512];
static long long bmplcn = -sizeof(buffer) - 1; /* Which bit of $Bitmap is in the buffer */
static long long bmplcn = -(sizeof(buffer) << 3);
int byte, bit;
ntfs_attr *attr;
@ -635,7 +694,8 @@ int utils_cluster_in_use(ntfs_volume *vol, long long lcn)
memset(buffer, 0xFF, sizeof(buffer));
bmplcn = lcn & (~((sizeof(buffer) << 3) - 1));
if (ntfs_attr_pread(attr, (bmplcn>>3), sizeof(buffer), buffer) < 0) {
if (ntfs_attr_pread(attr, (bmplcn >> 3), sizeof(buffer),
buffer) < 0) {
ntfs_log_perror("Couldn't read $Bitmap");
ntfs_attr_close(attr);
return -1;
@ -647,7 +707,9 @@ int utils_cluster_in_use(ntfs_volume *vol, long long lcn)
bit = 1 << (lcn & 7);
byte = (lcn >> 3) & (sizeof(buffer) - 1);
ntfs_log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] & bit);
ntfs_log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, "
"in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] &
bit);
return (buffer[byte] & bit);
}
@ -673,15 +735,15 @@ int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref)
{
static u8 buffer[512];
static s64 bmpmref = -sizeof(buffer) - 1; /* Which bit of $BITMAP is in the buffer */
int byte, bit;
ntfs_log_trace("Entering.\n");
if (!vol) {
errno = EINVAL;
return -1;
}
ntfs_log_trace("entering\n");
/* Does mref lie in the section of $Bitmap we already have cached? */
if (((s64)MREF(mref) < bmpmref) || ((s64)MREF(mref) >= (bmpmref +
(sizeof(buffer) << 3)))) {
@ -756,7 +818,7 @@ int utils_is_metadata(ntfs_inode *inode)
file = inode->mrec;
if (file && (file->base_mft_record != 0)) {
num = MREF(file->base_mft_record);
num = MREF_LE(file->base_mft_record);
if (__metadata(vol, num) == 1)
return 1;
}
@ -769,7 +831,7 @@ int utils_is_metadata(ntfs_inode *inode)
/* We know this will always be resident. */
attr = (FILE_NAME_ATTR *)((char *)rec + le16_to_cpu(rec->value_offset));
num = MREF(attr->parent_directory);
num = MREF_LE(attr->parent_directory);
if ((num != FILE_root) && (__metadata(vol, num) == 1))
return 1;
@ -970,10 +1032,9 @@ int mft_next_record(struct mft_search_ctx *ctx)
ctx->inode->mft_no = ctx->mft_num;
ctx->inode->vol = ctx->vol;
ctx->inode->mrec = malloc(ctx->vol->mft_record_size);
ctx->inode->mrec = ntfs_malloc(ctx->vol->mft_record_size);
if (!ctx->inode->mrec) {
free(ctx->inode); // == ntfs_inode_close
ntfs_log_error("Out of memory. Aborting.\n");
return -1;
}

View File

@ -52,15 +52,11 @@ int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref);
int utils_is_metadata(ntfs_inode *inode);
void utils_dump_mem(void *buf, int start, int length, int flags);
#ifndef _NTFS_RICH_H_
ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft);
#endif
#if !(defined(_NTFS_VOLUME_H) && defined(NTFS_RICH))
int utils_valid_device(const char *name, int force);
ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force);
#endif
ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags);
/**
* defines...
@ -154,4 +150,14 @@ static __inline__ int ntfs_mbstoucs_libntfscompat(const char *ins,
return ntfs_mbstoucs(ins, outs);
}
/* This simple utility function was missing from libntfs-3g. */
static __inline__ ntfschar *ntfs_attr_get_name(ATTR_RECORD *attr)
{
return (ntfschar*)((u8*)attr + le16_to_cpu(attr->name_offset));
}
/* The define 'leMFT_REF' is not present in libntfs-3g. It is only symbolic so
* typedef it to MFT_REF.*/
typedef MFT_REF leMFT_REF;
#endif /* _NTFS_UTILS_H_ */