From 8fc9c9630598492b193e1932db4a4176f8ad939c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 08:44:38 +0200 Subject: [PATCH 01/86] Reworked decisions to undo related to unreadable records When an INDX or MFT record could not be read while undoing the creation of this record, there is nothing to do. However if this was undoing the deletion of the last entry in an index, a new void index block has to be created. --- ntfsprogs/playlog.c | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/ntfsprogs/playlog.c b/ntfsprogs/playlog.c index 00fa8c67..d8ba333d 100644 --- a/ntfsprogs/playlog.c +++ b/ntfsprogs/playlog.c @@ -4731,10 +4731,16 @@ printf("record lsn 0x%llx is %s than action %d lsn 0x%llx\n", err = 1; } } else { - /* Undoing a record create which was not done ? */ -// TODO make sure this is about a newly allocated record (with bad fixup) -// TODO check this is inputting a full record (record lth == data lth) - buffer = (char*)calloc(1, mftrecsz); + /* + * Could not read the MFT record : + * if this is undoing a record create (from scratch) + * which did not take place, there is nothing to redo, + * otherwise this is an error. + */ + if (check_full_mft(action,TRUE)) + executed = FALSE; + else + err = 1; } break; case ON_INDX : @@ -4765,13 +4771,28 @@ printf("index lsn 0x%llx is %s than action %d lsn 0x%llx\n", err = 1; } } else { - /* Undoing a record create which was not done ? */ -// TODO make sure this is about a newly allocated record (with bad fixup) -// TODO check this is inputting a full record (record lth == data lth) -// recreate an INDX record if this is the first entry - buffer = (char*)calloc(1, xsize); - err = create_indx(vol, action, buffer); - executed = TRUE; + /* + * Could not read the INDX record : + * if this is undoing a record create (from scratch) + * which did not take place, there is nothing to redo, + * otherwise this must be an error. + * However, after deleting the last index allocation + * in a block, the block is apparently zeroed + * and cannot be read. In this case we have to + * create an initial index block and apply the undo. + */ + if (check_full_index(action,TRUE)) + executed = FALSE; + else { + err = 1; + if (uop == AddIndexEntryAllocation) { + executed = TRUE; + buffer = (char*)calloc(1, xsize); + if (buffer) + err = create_indx(vol, + action, buffer); + } + } } break; case ON_RAW : From 8e550e712d9f2b998b627005bc190678b50c3754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 08:51:36 +0200 Subject: [PATCH 02/86] Added an option for preserving the full log file in ntfsclone Usually, only a few pages of the Windows log file are saved in an ntfsclone image. This is inappropriate for building reference images for recovering the log, and the --full-logfile option serves that purpose. --- ntfsprogs/ntfsclone.8.in | 7 +++++-- ntfsprogs/ntfsclone.c | 25 ++++++++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/ntfsprogs/ntfsclone.8.in b/ntfsprogs/ntfsclone.8.in index d156634c..9be43f18 100644 --- a/ntfsprogs/ntfsclone.8.in +++ b/ntfsprogs/ntfsclone.8.in @@ -235,8 +235,11 @@ inconsistency are saved too. Do not wipe the timestamps, to be used only with the .B \-\-metadata option. - - +.TP +\fB\-\-full\-logfile\fR +Include the Windows log file in the copy. This is only useful for +extracting metadata, saving or cloning a file system which was not +properly unmounted from Windows. .TP \fB\-\-new\-serial\fR, or .TP diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index cbbbc854..4ccb0168 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -3,7 +3,7 @@ * * Copyright (c) 2003-2006 Szabolcs Szakacsits * Copyright (c) 2004-2006 Anton Altaparmakov - * Copyright (c) 2010-2015 Jean-Pierre Andre + * Copyright (c) 2010-2016 Jean-Pierre Andre * Special image format support copyright (c) 2004 Per Olofsson * * Clone NTFS data and/or metadata to a sparse file, image, device or stdout. @@ -160,6 +160,7 @@ static struct { int new_serial; int metadata_image; int preserve_timestamps; + int full_logfile; int restore_image; char *output; char *volume; @@ -368,6 +369,7 @@ static void usage(int ret) " -t, --preserve-timestamps Do not clear the timestamps\n" " -q, --quiet Do not display any progress bars\n" " -f, --force Force to progress (DANGEROUS)\n" + " --full-logfile Include the full logfile in metadata output\n" " -h, --help Display this help\n" #ifdef DEBUG " -d, --debug Show debug information\n" @@ -391,7 +393,7 @@ static void version(void) "Efficiently clone, image, restore or rescue an NTFS Volume.\n\n" "Copyright (c) 2003-2006 Szabolcs Szakacsits\n" "Copyright (c) 2004-2006 Anton Altaparmakov\n" - "Copyright (c) 2010-2015 Jean-Pierre Andre\n\n"); + "Copyright (c) 2010-2016 Jean-Pierre Andre\n\n"); fprintf(stderr, "%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); exit(0); } @@ -415,6 +417,7 @@ static void parse_options(int argc, char **argv) { "rescue", no_argument, NULL, 'R' }, { "new-serial", no_argument, NULL, 'I' }, { "new-half-serial", no_argument, NULL, 'i' }, + { "full-logfile", no_argument, NULL, 'l' }, { "save-image", no_argument, NULL, 's' }, { "preserve-timestamps", no_argument, NULL, 't' }, { "version", no_argument, NULL, 'V' }, @@ -451,6 +454,9 @@ static void parse_options(int argc, char **argv) case 'I': /* not proposed as a short option */ opt.new_serial |= 2; break; + case 'l': + opt.full_logfile++; + break; case 'm': opt.metadata++; break; @@ -633,7 +639,7 @@ static s64 is_critical_metadata(ntfs_walk_clusters_ctx *image, runlist *rl) if (inode == FILE_BadClus && image->ctx->attr->type == AT_DATA) return 0; - if (inode != FILE_LogFile) + if ((inode != FILE_LogFile) || opt.full_logfile) return rl->length; if (image->ctx->attr->type == AT_DATA) { @@ -2150,11 +2156,20 @@ static void mount_volume(unsigned long new_mntflag) * Normally avoided in order to get the original log file * data, but needed when remounting the metadata of a * volume improperly unmounted from Windows. + * If the full log file was requested, it must be kept + * as is, so we just remount read-only. */ if (!(new_mntflag & (NTFS_MNT_RDONLY | NTFS_MNT_RECOVER))) { - Printf("Trying to recover...\n"); - vol = ntfs_mount(opt.volume, + if (opt.full_logfile) { + Printf("Retrying read-only to ignore" + " the log file...\n"); + vol = ntfs_mount(opt.volume, + new_mntflag | NTFS_MNT_RDONLY); + } else { + Printf("Trying to recover...\n"); + vol = ntfs_mount(opt.volume, new_mntflag | NTFS_MNT_RECOVER); + } Printf("... %s\n",(vol ? "Successful" : "Failed")); } if (!vol) From da33b0328fcd41450447a024fde962c0206ca695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 09:10:35 +0200 Subject: [PATCH 03/86] Used plugins to process reparse points The new "system compression" files used by Windows 10 make use of reparse points to record the compression parameters, and a specific named data stream is used to store the compressed data. With this patch, processing of reparse points can be done by an external plugin only loaded as needed. Junctions and symlinks, which are also based on reparse points, are now processed by "internal plugins". --- README | 7 +- configure.ac | 10 + include/ntfs-3g/Makefile.am | 3 +- include/ntfs-3g/plugin.h | 137 +++++++++++++ include/ntfs-3g/reparse.h | 2 + libntfs-3g/reparse.c | 30 ++- src/Makefile.am | 20 +- src/lowntfs-3g.c | 371 ++++++++++++++++++++++++++++++----- src/ntfs-3g.c | 380 +++++++++++++++++++++++++++++++----- src/ntfs-3g_common.c | 114 ++++++++++- src/ntfs-3g_common.h | 29 +++ 11 files changed, 988 insertions(+), 115 deletions(-) create mode 100644 include/ntfs-3g/plugin.h diff --git a/README b/README index 0f6a7db2..daf5ccf2 100644 --- a/README +++ b/README @@ -16,8 +16,10 @@ reliability and feature richness per invested effort wise. Besides the common file system features, NTFS-3G has support for file ownership and permissions, POSIX ACLs, junction points, extended attributes -and creating compressed files. Parameter files in the directory .NTFS-3G may -be required to enable them, please get the instructions from +and creating internally compressed files (parameter files in the directory +.NTFS-3G may be required to enable them). The new compressed file formats +available in Windows 10 can also be read through a plugin. For using +advanced features, please get the instructions from http://www.tuxera.com/community/ntfs-3g-advanced/ @@ -59,6 +61,7 @@ typing : Below are a few specific options to ./configure : --disable-ntfsprogs : do not build the ntfsprogs tools, + --disable-plugins : disable support for plugins --enable-posix-acls : enable support for Posix ACLs --enable-xattr-mappings : enable system extended attributes mappings --with-fuse=external : use external fuse (overriding Linux default) diff --git a/configure.ac b/configure.ac index d31a9cda..b14b00af 100644 --- a/configure.ac +++ b/configure.ac @@ -121,6 +121,14 @@ AC_ARG_ENABLE( [enable_xattr_mappings="no"] ) +AC_ARG_ENABLE( + [plugins], + [AS_HELP_STRING([--disable-plugins], [Disable external reparse point + plugins for the ntfs-3g FUSE driver])], + , + [disable_plugins="no"] +) + AC_ARG_ENABLE( [device-default-io-ops], [AS_HELP_STRING([--disable-device-default-io-ops],[install default IO ops])], @@ -566,6 +574,7 @@ test "${enable_device_default_io_ops}" = "no" && AC_DEFINE( test "${enable_mtab}" = "no" && AC_DEFINE([IGNORE_MTAB], [1], [Don't update /etc/mtab]) test "${enable_posix_acls}" != "no" && AC_DEFINE([POSIXACLS], [1], [POSIX ACL support]) test "${enable_xattr_mappings}" != "no" && AC_DEFINE([XATTR_MAPPINGS], [1], [system extended attributes mappings]) +test "${disable_plugins}" != "no" && AC_DEFINE([DISABLE_PLUGINS], [1], [Define to 1 for disabling reparse plugins]) test "${enable_really_static}" = "yes" && enable_library="no" test "${enable_library}" = "no" && enable_ldconfig="no" @@ -617,6 +626,7 @@ AM_CONDITIONAL([ENABLE_NTFS_3G], [test "${enable_ntfs_3g}" = "yes"]) AM_CONDITIONAL([ENABLE_NTFSPROGS], [test "${enable_ntfsprogs}" = "yes"]) AM_CONDITIONAL([ENABLE_EXTRAS], [test "${enable_extras}" = "yes"]) AM_CONDITIONAL([ENABLE_QUARANTINED], [test "${enable_quarantined}" = "yes"]) +AM_CONDITIONAL([DISABLE_PLUGINS], [test "${disable_plugins}" != "no"]) # workaround for flags indicates the kind of opening. + * The field fi->fh may be used to store some information which + * will be available to subsequent reads and writes. When used + * this field must be non-null. + * The returned value is zero for success and a negative errno + * value for failure. + */ + int (*open)(ntfs_inode *ni, const REPARSE_POINT *reparse, + struct fuse_file_info *fi); + + /* + * Release an open file + * This is only called if fi->fh has been set to a non-null + * value while opening. It may be used to free some context + * specific to the open file. + * The returned value is zero for success or a negative errno + * value for failure. + */ + int (*release)(ntfs_inode *ni, const REPARSE_POINT *reparse, + struct fuse_file_info *fi); + + /* + * Read from an open file + * The returned value is the count of bytes which were read + * or a negative errno value for failure. + * If the returned value is positive, the access time stamp + * will be updated after the call. + */ + int (*read)(ntfs_inode *ni, const REPARSE_POINT *reparse, + char *buf, size_t size, + off_t offset, struct fuse_file_info *fi); + + /* + * Write to an open file + * The file system must be left consistent after each write call, + * the file itself must be at least deletable if the application + * writing to it is killed for some reason. + * The returned value is the count of bytes which were written + * or a negative errno value for failure. + * If the returned value is positive, the modified time stamp + * will be updated after the call. + */ + int (*write)(ntfs_inode *ni, const REPARSE_POINT *reparse, + const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi); + + /* + * Get a symbolic link + * The symbolic link must be returned in an allocated buffer, + * encoded in a zero terminated multibyte string compatible + * which the locale mount option. + * The returned value is zero for success or a negative errno + * value for failure. + */ + int (*readlink)(ntfs_inode *ni, const REPARSE_POINT *reparse, + char **pbuf); + + /* + * Truncate a file (shorten or append zeroes) + * The returned value is zero for success or a negative errno + * value for failure. + * If the returned value is zero, the modified time stamp + * will be updated after the call. + */ + int (*truncate)(ntfs_inode *ni, const REPARSE_POINT *reparse, + off_t size); +} plugin_operations_t; + + +/* + * Plugin initialization routine + * Returns the entry table if successful, otherwise returns NULL + * and sets errno (e.g. to EINVAL if the tag is not supported by + * the plugin.) + */ +typedef const struct plugin_operations *(*plugin_init_t)(le32 tag); +const struct plugin_operations *init(le32 tag); + +#endif /* PLUGIN_H */ diff --git a/include/ntfs-3g/reparse.h b/include/ntfs-3g/reparse.h index 35f4aa45..27e90509 100644 --- a/include/ntfs-3g/reparse.h +++ b/include/ntfs-3g/reparse.h @@ -30,6 +30,8 @@ BOOL ntfs_possible_symlink(ntfs_inode *ni); int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size); +REPARSE_POINT *ntfs_get_reparse_point(ntfs_inode *ni); + int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value, size_t size, int flags); int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni); diff --git a/libntfs-3g/reparse.c b/libntfs-3g/reparse.c index fe9d361b..5e2f403e 100644 --- a/libntfs-3g/reparse.c +++ b/libntfs-3g/reparse.c @@ -3,7 +3,7 @@ * * This module is part of ntfs-3g library * - * Copyright (c) 2008-2014 Jean-Pierre Andre + * Copyright (c) 2008-2016 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -1256,3 +1256,31 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni) } #endif /* HAVE_SETXATTR */ + +/* + * Get the reparse data into a buffer + * + * Returns the buffer if the reparse data exists and is valid + * NULL otherwise (with errno set according to the cause). + * When a buffer is returned, it has to be freed by caller. + */ + +REPARSE_POINT *ntfs_get_reparse_point(ntfs_inode *ni) +{ + s64 attr_size = 0; + REPARSE_POINT *reparse_attr; + + reparse_attr = (REPARSE_POINT*)NULL; + if (ni) { + reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni, + AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size); + if (reparse_attr + && !valid_reparse_data(ni, reparse_attr, attr_size)) { + free(reparse_attr); + reparse_attr = (REPARSE_POINT*)NULL; + errno = ENOENT; + } + } else + errno = EINVAL; + return (reparse_attr); +} diff --git a/src/Makefile.am b/src/Makefile.am index 7fd4af45..4edbcbc4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,11 @@ FUSE_CFLAGS = $(FUSE_MODULE_CFLAGS) FUSE_LIBS = $(FUSE_MODULE_LIBS) endif +if !DISABLE_PLUGINS +plugindir = $(libdir)/ntfs-3g +PLUGIN_CFLAGS = -DPLUGIN_DIR=\"$(plugindir)\" +endif + if ENABLE_NTFS_3G bin_PROGRAMS = ntfs-3g.probe \ @@ -22,7 +27,7 @@ man_MANS = ntfs-3g.8 ntfs-3g.probe.8 \ ntfs-3g.usermap.8 \ ntfs-3g.secaudit.8 -ntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la +ntfs_3g_LDADD = -ldl $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la if REALLYSTATIC ntfs_3g_LDFLAGS = $(AM_LDFLAGS) -all-static endif @@ -30,10 +35,11 @@ ntfs_3g_CFLAGS = \ $(AM_CFLAGS) \ -DFUSE_USE_VERSION=26 \ $(FUSE_CFLAGS) \ - -I$(top_srcdir)/include/ntfs-3g + -I$(top_srcdir)/include/ntfs-3g \ + $(PLUGIN_CFLAGS) ntfs_3g_SOURCES = ntfs-3g.c ntfs-3g_common.c -lowntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la +lowntfs_3g_LDADD = -ldl $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la if REALLYSTATIC lowntfs_3g_LDFLAGS = $(AM_LDFLAGS) -all-static endif @@ -41,7 +47,8 @@ lowntfs_3g_CFLAGS = \ $(AM_CFLAGS) \ -DFUSE_USE_VERSION=26 \ $(FUSE_CFLAGS) \ - -I$(top_srcdir)/include/ntfs-3g + -I$(top_srcdir)/include/ntfs-3g \ + $(PLUGIN_CFLAGS) lowntfs_3g_SOURCES = lowntfs-3g.c ntfs-3g_common.c ntfs_3g_probe_LDADD = $(top_builddir)/libntfs-3g/libntfs-3g.la @@ -61,10 +68,13 @@ ntfs_3g_secaudit_SOURCES = secaudit.c drivers : $(FUSE_LIBS) ntfs-3g lowntfs-3g -if RUN_LDCONFIG install-exec-hook: +if RUN_LDCONFIG $(LDCONFIG) endif +if !DISABLE_PLUGINS + $(MKDIR_P) $(DESTDIR)/$(plugindir) +endif if ENABLE_MOUNT_HELPER install-exec-local: install-rootbinPROGRAMS diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 0bb38f97..899586c1 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -4,7 +4,7 @@ * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2005 Yuval Fledel * Copyright (c) 2006-2009 Szabolcs Szakacsits - * Copyright (c) 2007-2015 Jean-Pierre Andre + * Copyright (c) 2007-2016 Jean-Pierre Andre * Copyright (c) 2009 Erik Larsson * * This file is originated from the Linux-NTFS project. @@ -105,6 +105,7 @@ #include "xattrs.h" #include "misc.h" #include "ioctl.h" +#include "plugin.h" #include "ntfs-3g_common.h" @@ -157,6 +158,22 @@ #define set_archive(ni) (ni)->flags |= FILE_ATTR_ARCHIVE #define INODE(ino) ((ino) == 1 ? (MFT_REF)FILE_root : (MFT_REF)(ino)) +/* + * Call a function from a reparse plugin (variable arguments) + * Requires "reparse" and "ops" to have been defined + * + * Returns a non-negative value if successful, + * and a negative error code if something fails. + */ +#define CALL_REPARSE_PLUGIN(ni, op_name, ...) \ + (reparse = (REPARSE_POINT*)NULL, \ + ops = select_reparse_plugin(ctx, ni, &reparse), \ + (!ops ? -errno \ + : (ops->op_name ? \ + ops->op_name(ni, reparse, __VA_ARGS__) \ + : -EOPNOTSUPP))), \ + free(reparse) + typedef enum { FSTYPE_NONE, FSTYPE_UNKNOWN, @@ -187,13 +204,17 @@ struct open_file { fuse_ino_t ino; fuse_ino_t parent; int state; +#ifndef PLUGINS_DISABLED + struct fuse_file_info fi; +#endif /* PLUGINS_DISABLED */ } ; enum { CLOSE_GHOST = 1, CLOSE_COMPRESSED = 2, CLOSE_ENCRYPTED = 4, - CLOSE_DMTIME = 8 + CLOSE_DMTIME = 8, + CLOSE_REPARSE = 16 }; enum RM_TYPES { @@ -598,6 +619,67 @@ static void ntfs_init(void *userdata __attribute__((unused)), #endif /* defined(FUSE_CAP_IOCTL_DIR) */ } +#ifndef PLUGINS_DISABLED + +/* + * Define attributes for a junction or symlink + * (internal plugin) + */ + +static int junction_getstat(ntfs_inode *ni, + const REPARSE_POINT *reparse __attribute__((unused)), + struct stat *stbuf) +{ + char *target; + int attr_size; + int res; + + errno = 0; + target = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size); + /* + * If the reparse point is not a valid + * directory junction, and there is no error + * we still display as a symlink + */ + if (target || (errno == EOPNOTSUPP)) { + /* returning attribute size */ + if (target) + stbuf->st_size = attr_size; + else + stbuf->st_size = sizeof(ntfs_bad_reparse); + stbuf->st_blocks = (ni->allocated_size + 511) >> 9; + stbuf->st_mode = S_IFLNK; + free(target); + res = 0; + } else { + res = -errno; + } + return (res); +} + +/* + * Apply permission masks to st_mode returned by reparse handler + */ + +static void apply_umask(struct stat *stbuf) +{ + switch (stbuf->st_mode & S_IFMT) { + case S_IFREG : + stbuf->st_mode &= ~ctx->fmask; + break; + case S_IFDIR : + stbuf->st_mode &= ~ctx->dmask; + break; + case S_IFLNK : + stbuf->st_mode = (stbuf->st_mode & S_IFMT) | 0777; + break; + default : + break; + } +} + +#endif /* PLUGINS_DISABLED */ + static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, struct stat *stbuf) { @@ -607,9 +689,27 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx, memset(stbuf, 0, sizeof(struct stat)); withusermapping = (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL); + stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) || (ni->flags & FILE_ATTR_REPARSE_POINT)) { if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + res = CALL_REPARSE_PLUGIN(ni, getattr, stbuf); + if (!res) { + apply_umask(stbuf); + } else { + stbuf->st_size = + sizeof(ntfs_bad_reparse); + stbuf->st_blocks = + (ni->allocated_size + 511) >> 9; + stbuf->st_mode = S_IFLNK; + res = 0; + } + goto ok; +#else /* PLUGINS_DISABLED */ char *target; int attr_size; @@ -638,6 +738,7 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx, res = -errno; goto exit; } +#endif /* PLUGINS_DISABLED */ } else { /* Directory. */ stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask); @@ -676,7 +777,6 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx, * See more on the ntfs-3g-devel list. */ stbuf->st_blocks = (ni->allocated_size + 511) >> 9; - stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); if (ni->flags & FILE_ATTR_SYSTEM) { na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); if (!na) { @@ -742,6 +842,9 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx, } stbuf->st_mode |= (0777 & ~ctx->fmask); } +#ifndef PLUGINS_DISABLED +ok: +#endif /* PLUGINS_DISABLED */ if (withusermapping) { if (ntfs_get_owner_mode(scx,ni,stbuf) < 0) set_fuse_error(&res); @@ -884,6 +987,36 @@ static void ntfs_fuse_lookup(fuse_req_t req, fuse_ino_t parent, fuse_reply_entry(req, &entry); } +#ifndef PLUGINS_DISABLED + +/* + * Get the link defined by a junction or symlink + * (internal plugin) + */ + +static int junction_readlink(ntfs_inode *ni, + const REPARSE_POINT *reparse __attribute__((unused)), + char **pbuf) +{ + int attr_size; + int res; + + errno = 0; + res = 0; + *pbuf = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size); + if (!*pbuf) { + if (errno == EOPNOTSUPP) { + *pbuf = strdup(ntfs_bad_reparse); + if (!*pbuf) + res = -errno; + } else + res = -errno; + } + return (res); +} + +#endif /* PLUGINS_DISABLED */ + static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino) { ntfs_inode *ni = NULL; @@ -902,6 +1035,17 @@ static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino) * Reparse point : analyze as a junction point */ if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + res = CALL_REPARSE_PLUGIN(ni, readlink, &buf); + if (res) { + buf = strdup(ntfs_bad_reparse); + if (!buf) + res = -errno; + } +#else /* PLUGINS_DISABLED */ int attr_size; errno = 0; @@ -913,7 +1057,8 @@ static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino) if (!buf) res = -errno; } - goto exit; +#endif /* PLUGINS_DISABLED */ + goto exit; } /* Sanity checks. */ if (!(ni->flags & FILE_ATTR_SYSTEM)) { @@ -1266,10 +1411,9 @@ static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { ntfs_inode *ni; - ntfs_attr *na; + ntfs_attr *na = NULL; struct open_file *of; int state = 0; - char *path = NULL; int res = 0; #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) int accesstype; @@ -1278,56 +1422,77 @@ static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino, ni = ntfs_inode_open(ctx->vol, INODE(ino)); if (ni) { - na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); - if (na) { + if (!(ni->flags & FILE_ATTR_REPARSE_POINT)) { + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + res = -errno; + goto close; + } + } #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) - if (ntfs_fuse_fill_security_context(req, &security)) { - if (fi->flags & O_WRONLY) - accesstype = S_IWRITE; + if (ntfs_fuse_fill_security_context(req, &security)) { + if (fi->flags & O_WRONLY) + accesstype = S_IWRITE; + else + if (fi->flags & O_RDWR) + accesstype = S_IWRITE | S_IREAD; else - if (fi->flags & O_RDWR) - accesstype = S_IWRITE | S_IREAD; - else - accesstype = S_IREAD; - /* check whether requested access is allowed */ - if (!ntfs_allowed_access(&security, - ni,accesstype)) - res = -EACCES; - } + accesstype = S_IREAD; + /* check whether requested access is allowed */ + if (!ntfs_allowed_access(&security, + ni,accesstype)) + res = -EACCES; + } #endif - if ((res >= 0) - && (fi->flags & (O_WRONLY | O_RDWR))) { - /* mark a future need to compress the last chunk */ - if (na->data_flags & ATTR_COMPRESSION_MASK) - state |= CLOSE_COMPRESSED; -#ifdef HAVE_SETXATTR /* extended attributes interface required */ - /* mark a future need to fixup encrypted inode */ - if (ctx->efs_raw - && !(na->data_flags & ATTR_IS_ENCRYPTED) - && (ni->flags & FILE_ATTR_ENCRYPTED)) - state |= CLOSE_ENCRYPTED; -#endif /* HAVE_SETXATTR */ - /* mark a future need to update the mtime */ - if (ctx->dmtime) - state |= CLOSE_DMTIME; - /* deny opening metadata files for writing */ - if (ino < FILE_first_user) - res = -EPERM; + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + fi->fh = 0; + res = CALL_REPARSE_PLUGIN(ni, open, fi); + if (!res && fi->fh) { + state = CLOSE_REPARSE; } - ntfs_attr_close(na); - } else - res = -errno; +#else /* PLUGINS_DISABLED */ + res = -EOPNOTSUPP; +#endif /* PLUGINS_DISABLED */ + goto close; + } + if ((res >= 0) + && (fi->flags & (O_WRONLY | O_RDWR))) { + /* mark a future need to compress the last chunk */ + if (na->data_flags & ATTR_COMPRESSION_MASK) + state |= CLOSE_COMPRESSED; +#ifdef HAVE_SETXATTR /* extended attributes interface required */ + /* mark a future need to fixup encrypted inode */ + if (ctx->efs_raw + && !(na->data_flags & ATTR_IS_ENCRYPTED) + && (ni->flags & FILE_ATTR_ENCRYPTED)) + state |= CLOSE_ENCRYPTED; +#endif /* HAVE_SETXATTR */ + /* mark a future need to update the mtime */ + if (ctx->dmtime) + state |= CLOSE_DMTIME; + /* deny opening metadata files for writing */ + if (ino < FILE_first_user) + res = -EPERM; + } + ntfs_attr_close(na); +close: if (ntfs_inode_close(ni)) set_fuse_error(&res); } else res = -errno; - free(path); if (res >= 0) { of = (struct open_file*)malloc(sizeof(struct open_file)); if (of) { of->parent = 0; of->ino = ino; of->state = state; +#ifdef PLUGIN_ENABLED + memcpy(&of->fi, fi, sizeof(struct fuse_file_info)); +#endif /* PLUGIN_ENABLED */ of->next = ctx->open_files; of->previous = (struct open_file*)NULL; if (ctx->open_files) @@ -1368,6 +1533,22 @@ static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, res = -errno; goto exit; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + struct open_file *of; + + of = (struct open_file*)fi; + res = CALL_REPARSE_PLUGIN(ni, read, buf, size, offset, &of->fi); + if (res >= 0) { + goto stamps; + } +#else /* PLUGINS_DISABLED */ + res = -EOPNOTSUPP; +#endif /* PLUGINS_DISABLED */ + goto exit; + } na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); if (!na) { res = -errno; @@ -1403,8 +1584,11 @@ static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, total += ret; } ok: - ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME); res = total; +#ifndef PLUGINS_DISABLED +stamps : +#endif /* PLUGINS_DISABLED */ + ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); exit: if (na) ntfs_attr_close(na); @@ -1430,6 +1614,23 @@ static void ntfs_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf, res = -errno; goto exit; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + struct open_file *of; + + of = (struct open_file*)fi; + res = CALL_REPARSE_PLUGIN(ni, write, buf, size, offset, + &of->fi); + if (res >= 0) { + goto stamps; + } +#else /* PLUGINS_DISABLED */ + res = -EOPNOTSUPP; +#endif /* PLUGINS_DISABLED */ + goto exit; + } na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); if (!na) { res = -errno; @@ -1446,15 +1647,18 @@ static void ntfs_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf, total += ret; } res = total; +#ifndef PLUGINS_DISABLED +stamps : +#endif /* PLUGINS_DISABLED */ if ((res > 0) && (!ctx->dmtime || (sle64_to_cpu(ntfs_current_time()) - sle64_to_cpu(ni->last_data_change_time)) > ctx->dmtime)) - ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); + ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME); exit: if (na) ntfs_attr_close(na); - if (total) + if (res > 0) set_archive(ni); if (ntfs_inode_close(ni)) set_fuse_error(&res); @@ -1607,9 +1811,11 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, errno = EPERM; goto exit; } - na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); - if (!na) - goto exit; + if (!(ni->flags & FILE_ATTR_REPARSE_POINT)) { + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) + goto exit; + } #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) /* * deny truncation if cannot write to file @@ -1622,6 +1828,21 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, goto exit; } #endif + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + res = CALL_REPARSE_PLUGIN(ni, truncate, size); + if (!res) { + set_archive(ni); + goto stamps; + } +#else /* PLUGINS_DISABLED */ + res = -EOPNOTSUPP; +#endif /* PLUGINS_DISABLED */ + goto exit; + } /* * for compressed files, upsizing is done by inserting a final * zero, which is optimized as creating a hole when possible. @@ -1637,8 +1858,11 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino, goto exit; if (oldsize != size) set_archive(ni); - - ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); + +#ifndef PLUGINS_DISABLED +stamps : +#endif /* PLUGINS_DISABLED */ + ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME); res = ntfs_fuse_getstat(scx, ni, stbuf); errno = (res ? -res : 0); exit: @@ -2550,8 +2774,8 @@ static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino, of = (struct open_file*)(long)fi->fh; /* Only for marked descriptors there is something to do */ if (!of - || !(of->state & (CLOSE_COMPRESSED - | CLOSE_ENCRYPTED | CLOSE_DMTIME))) { + || !(of->state & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED + | CLOSE_DMTIME | CLOSE_REPARSE))) { res = 0; goto out; } @@ -2560,20 +2784,38 @@ static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino, res = -errno; goto exit; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + res = CALL_REPARSE_PLUGIN(ni, release, &of->fi); + if (!res) { + goto stamps; + } +#else /* PLUGINS_DISABLED */ + /* Assume release() was not needed */ + res = 0; +#endif /* PLUGINS_DISABLED */ + goto exit; + } na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); if (!na) { res = -errno; goto exit; } res = 0; - if (of->state & CLOSE_DMTIME) - ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME); if (of->state & CLOSE_COMPRESSED) res = ntfs_attr_pclose(na); #ifdef HAVE_SETXATTR /* extended attributes interface required */ if (of->state & CLOSE_ENCRYPTED) res = ntfs_efs_fixup_attribute(NULL, na); #endif /* HAVE_SETXATTR */ +#ifndef PLUGINS_DISABLED +stamps : +#endif /* PLUGINS_DISABLED */ + if (of->state & CLOSE_DMTIME) + ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME); exit: if (na) ntfs_attr_close(na); @@ -3568,6 +3810,20 @@ out : #endif #endif /* HAVE_SETXATTR */ +#ifndef PLUGINS_DISABLED +static void register_internal_reparse_plugins(void) +{ + static const plugin_operations_t ops = { + .getattr = junction_getstat, + .readlink = junction_readlink, + } ; + register_reparse_plugin(ctx, IO_REPARSE_TAG_MOUNT_POINT, + &ops, (void*)NULL); + register_reparse_plugin(ctx, IO_REPARSE_TAG_SYMLINK, + &ops, (void*)NULL); +} +#endif /* PLUGINS_DISABLED */ + static void ntfs_close(void) { struct SECURITY_CONTEXT security; @@ -4179,6 +4435,10 @@ int main(int argc, char *argv[]) free(ctx->xattrmap_path); #endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ +#ifndef PLUGINS_DISABLED + register_internal_reparse_plugins(); +#endif /* PLUGINS_DISABLED */ + se = mount_fuse(parsed_options); if (!se) { err = NTFS_VOLUME_FUSE_ERROR; @@ -4214,6 +4474,9 @@ err_out: #endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ err2: ntfs_close(); +#ifndef PLUGINS_DISABLED + close_reparse_plugins(ctx); +#endif /* PLUGINS_DISABLED */ free(ctx); free(parsed_options); free(opts.options); diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 268b0569..e3a23e58 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -4,7 +4,7 @@ * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2005 Yuval Fledel * Copyright (c) 2006-2009 Szabolcs Szakacsits - * Copyright (c) 2007-2015 Jean-Pierre Andre + * Copyright (c) 2007-2016 Jean-Pierre Andre * Copyright (c) 2009 Erik Larsson * * This file is originated from the Linux-NTFS project. @@ -99,6 +99,7 @@ #include "xattrs.h" #include "misc.h" #include "ioctl.h" +#include "plugin.h" #include "ntfs-3g_common.h" @@ -129,6 +130,22 @@ #define set_archive(ni) (ni)->flags |= FILE_ATTR_ARCHIVE +/* + * Call a function from a reparse plugin (variable arguments) + * Requires "reparse" and "ops" to have been defined + * + * Returns a non-negative value if successful, + * and a negative error code if something fails. + */ +#define CALL_REPARSE_PLUGIN(ni, op_name, ...) \ + (reparse = (REPARSE_POINT*)NULL, \ + ops = select_reparse_plugin(ctx, ni, &reparse), \ + (!ops ? -errno \ + : (ops->op_name ? \ + ops->op_name(ni, reparse, __VA_ARGS__) \ + : -EOPNOTSUPP))), \ + free(reparse) + typedef enum { FSTYPE_NONE, FSTYPE_UNKNOWN, @@ -144,7 +161,8 @@ typedef struct { enum { CLOSE_COMPRESSED = 1, CLOSE_ENCRYPTED = 2, - CLOSE_DMTIME = 4 + CLOSE_DMTIME = 4, + CLOSE_REPARSE = 8 }; static struct ntfs_options opts; @@ -663,6 +681,67 @@ static void *ntfs_init(struct fuse_conn_info *conn) return NULL; } +#ifndef PLUGINS_DISABLED + +/* + * Define attributes for a junction or symlink + * (internal plugin) + */ + +static int junction_getattr(ntfs_inode *ni, + const REPARSE_POINT *reparse __attribute__((unused)), + struct stat *stbuf) +{ + char *target; + int attr_size; + int res; + + errno = 0; + target = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size); + /* + * If the reparse point is not a valid + * directory junction, and there is no error + * we still display as a symlink + */ + if (target || (errno == EOPNOTSUPP)) { + /* returning attribute size */ + if (target) + stbuf->st_size = attr_size; + else + stbuf->st_size = sizeof(ntfs_bad_reparse); + stbuf->st_blocks = (ni->allocated_size + 511) >> 9; + stbuf->st_mode = S_IFLNK; + free(target); + res = 0; + } else { + res = -errno; + } + return (res); +} + +/* + * Apply permission masks to st_mode returned by a reparse handler + */ + +static void apply_umask(struct stat *stbuf) +{ + switch (stbuf->st_mode & S_IFMT) { + case S_IFREG : + stbuf->st_mode &= ~ctx->fmask; + break; + case S_IFDIR : + stbuf->st_mode &= ~ctx->dmask; + break; + case S_IFLNK : + stbuf->st_mode = (stbuf->st_mode & S_IFMT) | 0777; + break; + default : + break; + } +} + +#endif /* PLUGINS_DISABLED */ + static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) { int res = 0; @@ -696,10 +775,31 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) goto exit; } #endif + stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); + if (((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) || (ni->flags & FILE_ATTR_REPARSE_POINT)) && !stream_name_len) { if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + res = CALL_REPARSE_PLUGIN(ni, getattr, stbuf); + if (!res) { + apply_umask(stbuf); + goto ok; + } else { + stbuf->st_size = + sizeof(ntfs_bad_reparse); + stbuf->st_blocks = + (ni->allocated_size + 511) >> 9; + stbuf->st_mode = S_IFLNK; + res = 0; + goto ok; + } + goto exit; +#else /* PLUGINS_DISABLED */ char *target; int attr_size; @@ -724,6 +824,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) res = -errno; goto exit; } +#endif /* PLUGINS_DISABLED */ } else { /* Directory. */ stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask); @@ -761,7 +862,6 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) * See more on the ntfs-3g-devel list. */ stbuf->st_blocks = (ni->allocated_size + 511) >> 9; - stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) { na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); @@ -845,6 +945,9 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) } stbuf->st_mode |= (0777 & ~ctx->fmask); } +#ifndef PLUGINS_DISABLED +ok: +#endif /* PLUGINS_DISABLED */ if (withusermapping) { if (ntfs_get_owner_mode(&security,ni,stbuf) < 0) set_fuse_error(&res); @@ -900,6 +1003,36 @@ exit: return res; } +#ifndef PLUGINS_DISABLED + +/* + * Get the link defined by a junction or symlink + * (internal plugin) + */ + +static int junction_readlink(ntfs_inode *ni, + const REPARSE_POINT *reparse __attribute__((unused)), + char **pbuf) +{ + int attr_size; + int res; + + errno = 0; + res = 0; + *pbuf = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size); + if (!*pbuf) { + if (errno == EOPNOTSUPP) { + *pbuf = strdup(ntfs_bad_reparse); + if (!*pbuf) + res = -errno; + } else + res = -errno; + } + return (res); +} + +#endif /* PLUGINS_DISABLED */ + static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size) { char *path = NULL; @@ -926,6 +1059,21 @@ static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size) * Reparse point : analyze as a junction point */ if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + char *gotlink; + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + gotlink = (char*)NULL; + res = CALL_REPARSE_PLUGIN(ni, readlink, &gotlink); + if (gotlink) { + strncpy(buf, gotlink, buf_size); + free(gotlink); + } else { + strncpy(buf, ntfs_bad_reparse, buf_size); + res = 0; + } +#else /* PLUGINS_DISABLED */ char *target; int attr_size; @@ -940,6 +1088,7 @@ static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size) strcpy(buf,ntfs_bad_reparse); else res = -errno; +#endif /* PLUGINS_DISABLED */ goto exit; } /* Sanity checks. */ @@ -1163,7 +1312,7 @@ static int ntfs_fuse_open(const char *org_path, #endif { ntfs_inode *ni; - ntfs_attr *na; + ntfs_attr *na = NULL; int res = 0; char *path = NULL; ntfschar *stream_name; @@ -1178,50 +1327,66 @@ static int ntfs_fuse_open(const char *org_path, return stream_name_len; ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (ni) { - na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); - if (na) { -#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) - if (ntfs_fuse_fill_security_context(&security)) { - if (fi->flags & O_WRONLY) - accesstype = S_IWRITE; - else - if (fi->flags & O_RDWR) - accesstype = S_IWRITE | S_IREAD; - else - accesstype = S_IREAD; - /* - * directory must be searchable - * and requested access allowed - */ - if (!ntfs_allowed_dir_access(&security, - path,(ntfs_inode*)NULL,ni,S_IEXEC) - || !ntfs_allowed_access(&security, - ni,accesstype)) - res = -EACCES; + if (!(ni->flags & FILE_ATTR_REPARSE_POINT)) { + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + res = -errno; + goto close; } + } +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + if (ntfs_fuse_fill_security_context(&security)) { + if (fi->flags & O_WRONLY) + accesstype = S_IWRITE; + else + if (fi->flags & O_RDWR) + accesstype = S_IWRITE | S_IREAD; + else + accesstype = S_IREAD; + /* + * directory must be searchable + * and requested access allowed + */ + if (!ntfs_allowed_dir_access(&security, + path,(ntfs_inode*)NULL,ni,S_IEXEC) + || !ntfs_allowed_access(&security, + ni,accesstype)) + res = -EACCES; + } #endif - if ((res >= 0) - && (fi->flags & (O_WRONLY | O_RDWR))) { - /* mark a future need to compress the last chunk */ - if (na->data_flags & ATTR_COMPRESSION_MASK) - fi->fh |= CLOSE_COMPRESSED; + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + fi->fh = 0; + res = CALL_REPARSE_PLUGIN(ni, open, fi); +#else /* PLUGINS_DISABLED */ + res = -EOPNOTSUPP; +#endif /* PLUGINS_DISABLED */ + goto close; + } + if ((res >= 0) + && (fi->flags & (O_WRONLY | O_RDWR))) { + /* mark a future need to compress the last chunk */ + if (na->data_flags & ATTR_COMPRESSION_MASK) + fi->fh |= CLOSE_COMPRESSED; #ifdef HAVE_SETXATTR /* extended attributes interface required */ /* mark a future need to fixup encrypted inode */ - if (ctx->efs_raw - && !(na->data_flags & ATTR_IS_ENCRYPTED) - && (ni->flags & FILE_ATTR_ENCRYPTED)) - fi->fh |= CLOSE_ENCRYPTED; + if (ctx->efs_raw + && !(na->data_flags & ATTR_IS_ENCRYPTED) + && (ni->flags & FILE_ATTR_ENCRYPTED)) + fi->fh |= CLOSE_ENCRYPTED; #endif /* HAVE_SETXATTR */ - /* mark a future need to update the mtime */ - if (ctx->dmtime) - fi->fh |= CLOSE_DMTIME; - /* deny opening metadata files for writing */ - if (ni->mft_no < FILE_first_user) - res = -EPERM; - } - ntfs_attr_close(na); - } else - res = -errno; + /* mark a future need to update the mtime */ + if (ctx->dmtime) + fi->fh |= CLOSE_DMTIME; + /* deny opening metadata files for writing */ + if (ni->mft_no < FILE_first_user) + res = -EPERM; + } + ntfs_attr_close(na); +close: if (ntfs_inode_close(ni)) set_fuse_error(&res); } else @@ -1254,6 +1419,24 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, res = -errno; goto exit; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + if (stream_name_len || !fi) { + res = -EINVAL; + goto exit; + } + res = CALL_REPARSE_PLUGIN(ni, read, buf, size, offset, fi); + if (res >= 0) { + goto stamps; + } +#else /* PLUGINS_DISABLED */ + res = -EOPNOTSUPP; +#endif /* PLUGINS_DISABLED */ + goto exit; + } na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) { res = -errno; @@ -1289,8 +1472,11 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, total += ret; } ok: - ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME); res = total; +#ifndef PLUGINS_DISABLED +stamps: +#endif /* PLUGINS_DISABLED */ + ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); exit: if (na) ntfs_attr_close(na); @@ -1321,6 +1507,24 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, res = -errno; goto exit; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + if (stream_name_len || !fi) { + res = -EINVAL; + goto exit; + } + res = CALL_REPARSE_PLUGIN(ni, write, buf, size, offset, fi); + if (res >= 0) { + goto stamps; + } +#else /* PLUGINS_DISABLED */ + res = -EOPNOTSUPP; +#endif /* PLUGINS_DISABLED */ + goto exit; + } na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) { res = -errno; @@ -1337,15 +1541,18 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, total += ret; } res = total; +#ifndef PLUGINS_DISABLED +stamps: +#endif /* PLUGINS_DISABLED */ if ((res > 0) && (!ctx->dmtime || (sle64_to_cpu(ntfs_current_time()) - sle64_to_cpu(ni->last_data_change_time)) > ctx->dmtime)) - ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); + ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME); exit: if (na) ntfs_attr_close(na); - if (total) + if (res > 0) set_archive(ni); if (ntfs_inode_close(ni)) set_fuse_error(&res); @@ -1365,8 +1572,14 @@ static int ntfs_fuse_release(const char *org_path, ntfschar *stream_name; int stream_name_len, res; + if (!fi) { + res = -EINVAL; + goto out; + } + /* Only for marked descriptors there is something to do */ - if (!(fi->fh & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED | CLOSE_DMTIME))) { + + if (!fi->fh) { res = 0; goto out; } @@ -1380,20 +1593,42 @@ static int ntfs_fuse_release(const char *org_path, res = -errno; goto exit; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + if (stream_name_len) { + res = -EINVAL; + goto exit; + } + res = CALL_REPARSE_PLUGIN(ni, release, fi); + if (!res) { + goto stamps; + } +#else /* PLUGINS_DISABLED */ + /* Assume release() was not needed */ + res = 0; +#endif /* PLUGINS_DISABLED */ + goto exit; + } na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) { res = -errno; goto exit; } res = 0; - if (fi->fh & CLOSE_DMTIME) - ntfs_inode_update_times(na->ni,NTFS_UPDATE_MCTIME); if (fi->fh & CLOSE_COMPRESSED) res = ntfs_attr_pclose(na); #ifdef HAVE_SETXATTR /* extended attributes interface required */ if (fi->fh & CLOSE_ENCRYPTED) res = ntfs_efs_fixup_attribute(NULL, na); #endif /* HAVE_SETXATTR */ +#ifndef PLUGINS_DISABLED +stamps: +#endif /* PLUGINS_DISABLED */ + if (fi->fh & CLOSE_DMTIME) + ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME); exit: if (na) ntfs_attr_close(na); @@ -1440,6 +1675,25 @@ static int ntfs_fuse_trunc(const char *org_path, off_t size, goto exit; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + if (stream_name_len) { + res = -EINVAL; + goto exit; + } + res = CALL_REPARSE_PLUGIN(ni, truncate, size); + if (!res) { + set_archive(ni); + goto stamps; + } +#else /* PLUGINS_DISABLED */ + res = -EOPNOTSUPP; +#endif /* PLUGINS_DISABLED */ + goto exit; + } na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) goto exit; @@ -1472,8 +1726,11 @@ static int ntfs_fuse_trunc(const char *org_path, off_t size, goto exit; if (oldsize != size) set_archive(ni); - - ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME); + +#ifndef PLUGINS_DISABLED +stamps: +#endif /* PLUGINS_DISABLED */ + ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME); errno = 0; exit: res = -errno; @@ -3352,6 +3609,20 @@ exit: #endif #endif /* HAVE_SETXATTR */ +#ifndef PLUGINS_DISABLED +static void register_internal_reparse_plugins(void) +{ + static const plugin_operations_t ops = { + .getattr = junction_getattr, + .readlink = junction_readlink, + } ; + register_reparse_plugin(ctx, IO_REPARSE_TAG_MOUNT_POINT, + &ops, (void*)NULL); + register_reparse_plugin(ctx, IO_REPARSE_TAG_SYMLINK, + &ops, (void*)NULL); +} +#endif /* PLUGINS_DISABLED */ + static void ntfs_close(void) { struct SECURITY_CONTEXT security; @@ -3968,6 +4239,10 @@ int main(int argc, char *argv[]) free(ctx->xattrmap_path); #endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ +#ifndef PLUGINS_DISABLED + register_internal_reparse_plugins(); +#endif /* PLUGINS_DISABLED */ + fh = mount_fuse(parsed_options); if (!fh) { err = NTFS_VOLUME_FUSE_ERROR; @@ -4005,6 +4280,9 @@ err_out: #endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ err2: ntfs_close(); +#ifndef PLUGINS_DISABLED + close_reparse_plugins(ctx); +#endif /* PLUGINS_DISABLED */ free(ctx); free(parsed_options); free(opts.options); diff --git a/src/ntfs-3g_common.c b/src/ntfs-3g_common.c index 38ccd742..425e8102 100644 --- a/src/ntfs-3g_common.c +++ b/src/ntfs-3g_common.c @@ -1,7 +1,7 @@ /** * ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g. * - * Copyright (c) 2010-2015 Jean-Pierre Andre + * Copyright (c) 2010-2016 Jean-Pierre Andre * Copyright (c) 2010 Erik Larsson * * This program/include file is free software; you can redistribute it and/or @@ -28,6 +28,10 @@ #include #endif +#ifdef HAVE_DLFCN_H +#include +#endif + #ifdef HAVE_STRING_H #include #endif @@ -46,6 +50,8 @@ #include "inode.h" #include "security.h" #include "xattrs.h" +#include "reparse.h" +#include "plugin.h" #include "ntfs-3g_common.h" #include "realpath.h" #include "misc.h" @@ -750,3 +756,109 @@ exit : } #endif /* HAVE_SETXATTR */ + +#ifndef PLUGINS_DISABLED + +int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag, + const plugin_operations_t *ops, void *handle) +{ + plugin_list_t *plugin; + int res; + + res = -1; + plugin = (plugin_list_t*)ntfs_malloc(sizeof(plugin_list_t)); + if (plugin) { + plugin->tag = tag; + plugin->ops = ops; + plugin->handle = handle; + plugin->next = ctx->plugins; + ctx->plugins = plugin; + res = 0; + } + return (res); +} + +/* + * Get the reparse operations associated to an inode + * + * The plugin able to process the reparse point is dynamically loaded + * + * When successful, returns the operations vector and the reparse + * data if requested, + * Otherwise returns NULL, with errno set. + */ + +const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx, + ntfs_inode *ni, REPARSE_POINT **reparse_wanted) +{ + const struct plugin_operations *ops; + void *handle; + REPARSE_POINT *reparse; + le32 tag; + plugin_list_t *plugin; + plugin_init_t pinit; + + ops = (struct plugin_operations*)NULL; + reparse = ntfs_get_reparse_point(ni); + if (reparse) { + tag = reparse->reparse_tag; + for (plugin=ctx->plugins; plugin && (plugin->tag != tag); + plugin = plugin->next) { } + if (plugin) { + ops = plugin->ops; + } else { +#ifdef PLUGIN_DIR + char name[sizeof(PLUGIN_DIR) + 64]; + + snprintf(name,sizeof(name), PLUGIN_DIR + "/ntfs-plugin-%08lx.so", + (long)le32_to_cpu(tag)); +#else + char name[64]; + + snprintf(name,sizeof(name), "ntfs-plugin-%08lx.so", + (long)le32_to_cpu(tag)); +#endif + handle = dlopen(name, RTLD_LAZY); + if (handle) { + pinit = (plugin_init_t)dlsym(handle, "init"); + if (pinit) { + /* pinit() should set errno if it fails */ + ops = (*pinit)(tag); + if (ops && register_reparse_plugin(ctx, + tag, ops, handle)) + ops = (struct plugin_operations*)NULL; + } else + errno = ELIBBAD; + if (!ops) + dlclose(handle); + } else { + if (!(ctx->errors_logged & ERR_PLUGIN)) + ntfs_log_perror( + "Could not load plugin %s", + name); + ctx->errors_logged |= ERR_PLUGIN; + } + } + if (ops && reparse_wanted) + *reparse_wanted = reparse; + else + free(reparse); + } + return (ops); +} + +void close_reparse_plugins(ntfs_fuse_context_t *ctx) +{ + while (ctx->plugins) { + plugin_list_t *next; + + next = ctx->plugins->next; + if (ctx->plugins->handle) + dlclose(ctx->plugins->handle); + free(ctx->plugins); + ctx->plugins = next; + } +} + +#endif /* PLUGINS_DISABLED */ diff --git a/src/ntfs-3g_common.h b/src/ntfs-3g_common.h index 6e573a65..22452321 100644 --- a/src/ntfs-3g_common.h +++ b/src/ntfs-3g_common.h @@ -110,6 +110,21 @@ typedef enum { ATIME_RELATIVE } ntfs_atime_t; +typedef enum { + ERR_PLUGIN = 1 +} single_log_t; + +#ifndef PLUGINS_DISABLED + +typedef struct plugin_list { + struct plugin_list *next; + void *handle; + const plugin_operations_t *ops; + le32 tag; +} plugin_list_t; + +#endif /* PLUGINS_DISABLED */ + typedef struct { ntfs_volume *vol; unsigned int uid; @@ -145,8 +160,12 @@ typedef struct { struct fuse_chan *fc; BOOL inherit; unsigned int secure_flags; + single_log_t errors_logged; char *usermap_path; char *abs_mnt_point; +#ifndef PLUGINS_DISABLED + plugin_list_t *plugins; +#endif /* PLUGINS_DISABLED */ struct PERMISSIONS_CACHE *seccache; struct SECURITY_CONTEXT security; struct open_file *open_files; /* only defined in lowntfs-3g */ @@ -182,4 +201,14 @@ int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void), int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx, char *list, size_t size, BOOL prefixing); +#ifndef PLUGINS_DISABLED + +void close_reparse_plugins(ntfs_fuse_context_t *ctx); +const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx, + ntfs_inode *ni, REPARSE_POINT **reparse); +int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag, + const plugin_operations_t *ops, void *handle); + +#endif /* PLUGINS_DISABLED */ + #endif /* _NTFS_3G_COMMON_H */ From b6b100b58812997face892802e3e4ee75f6a1831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 09:27:07 +0200 Subject: [PATCH 04/86] Added clarification about creating a partition to the ntfsclone manual Try to make clear the option --output feeds data into a partition, but does not create the partition. --- ntfsprogs/ntfsclone.8.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsclone.8.in b/ntfsprogs/ntfsclone.8.in index 9be43f18..a1585c3c 100644 --- a/ntfsprogs/ntfsclone.8.in +++ b/ntfsprogs/ntfsclone.8.in @@ -185,12 +185,14 @@ Clone NTFS to the non\-existent If .I FILE is '\-' then clone to the -standard output. +standard output. This option cannot be used for creating a partition, +use \fB\-\-overwrite\fR for an existing partition. .TP \fB\-O\fR, \fB\-\-overwrite\fR FILE Clone NTFS to .IR FILE , -overwriting if exists. +which can be an existing partition or a regular file which will be +overwritten if it exists. .TP \fB\-s\fR, \fB\-\-save\-image\fR Save to the special image format. This is the most efficient way space and From 366c20e8a20efdc5244eb80c50170c5e26a8b1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 09:32:18 +0200 Subject: [PATCH 05/86] Silenced fixup warnings when allocating a new MFT record When creating a new MFT record, do not issue a warning if the current record has bad fixups. These warnings are meaningless, difficult to interpret and cause unneeded worries. --- libntfs-3g/mft.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libntfs-3g/mft.c b/libntfs-3g/mft.c index 304c5baa..29f1f4bc 100644 --- a/libntfs-3g/mft.c +++ b/libntfs-3g/mft.c @@ -1629,6 +1629,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni) int err; u32 usa_ofs; le16 seq_no, usn; + BOOL oldwarn; if (base_ni) ntfs_log_enter("Entering (allocating an extent mft record for " @@ -1742,10 +1743,22 @@ found_free_rec: if (!m) goto undo_mftbmp_alloc; + /* + * As this is allocating a new record, do not expect it to have + * been initialized previously, so do not warn over bad fixups + * (hence avoid warn flooding when an NTFS partition has been wiped). + */ + oldwarn = !NVolNoFixupWarn(vol); + NVolSetNoFixupWarn(vol); if (ntfs_mft_record_read(vol, bit, m)) { + if (oldwarn) + NVolClearNoFixupWarn(vol); free(m); goto undo_mftbmp_alloc; } + if (oldwarn) + NVolClearNoFixupWarn(vol); + /* Sanity check that the mft record is really not in use. */ if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) { ntfs_log_error("Inode %lld is used but it wasn't marked in " From fc666cb0b9643e0ad279062fb8d933659e7de5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 09:42:16 +0200 Subject: [PATCH 06/86] Fixed bad test in fuse mount Apply a fix from the full fuse library --- libfuse-lite/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfuse-lite/mount.c b/libfuse-lite/mount.c index 70454f4e..263c20a6 100644 --- a/libfuse-lite/mount.c +++ b/libfuse-lite/mount.c @@ -350,7 +350,7 @@ static int receive_fd(int fd) } cmsg = CMSG_FIRSTHDR(&msg); - if (!cmsg->cmsg_type == SCM_RIGHTS) { + if (cmsg->cmsg_type != SCM_RIGHTS) { fprintf(stderr, "got control message of unknown type %d\n", cmsg->cmsg_type); return -1; From 887d8f8294eb5c1437a1ae0a29ecc7878a536d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 09:44:59 +0200 Subject: [PATCH 07/86] Allowed kernel cacheing by lowntfs-3g when not using Posix ACLs Kernel cacheing of file attributes is usually not used by ntfs-3g, because it has defects when dealing with hard linked files and directory permission checks. Kernel cacheing is however possible when using lowntfs-3g and not using Posix ACLs. --- include/ntfs-3g/param.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/ntfs-3g/param.h b/include/ntfs-3g/param.h index 3210fab9..0b32cf80 100644 --- a/include/ntfs-3g/param.h +++ b/include/ntfs-3g/param.h @@ -115,8 +115,8 @@ enum { * * Possible values for low level : * 2 : no cache, kernel control - * 3 : use kernel/fuse cache, kernel control (external fuse >= 2.8) - * 5 : no cache, file system control (recommended on Linux) + * 3 : use kernel/fuse cache, kernel control (recommended) + * 5 : no cache, file system control * 6 : kernel/fuse cache, file system control (OpenIndiana only) * 8 : no cache, kernel control for ACLs * @@ -132,13 +132,14 @@ enum { */ #define HPERMSCONFIG 6 #define LPERMSCONFIG 6 -#else +#else /* defined(__sun) && defined(__SVR4) */ +/* + * Cacheing by kernel is buggy on Linux when access control is done + * by the file system, and also when using hard-linked files on + * the fuse high level interface. + */ #define HPERMSCONFIG 1 -#if defined(FUSE_INTERNAL) || !defined(FUSE_VERSION) || (FUSE_VERSION < 28) -#define LPERMSCONFIG 5 -#else #define LPERMSCONFIG 3 -#endif #endif /* defined(__sun) && defined(__SVR4) */ #endif /* defined _NTFS_PARAM_H */ From 8a1358fff439d2fe464ab67ba5d5394060880457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 09:51:47 +0200 Subject: [PATCH 08/86] Enabled fallback to read-only mount when volume is hibernated When a volume is found hibernated (or prepared for fast restarting), it is force-mounted as read-only. --- include/ntfs-3g/volume.h | 1 + libntfs-3g/volume.c | 42 ++++++++++++++++++++++++++++++---------- src/lowntfs-3g.c | 2 ++ src/ntfs-3g.c | 2 ++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index 2720864c..cee91e21 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -60,6 +60,7 @@ typedef struct _ntfs_volume ntfs_volume; enum { NTFS_MNT_NONE = 0x00000000, NTFS_MNT_RDONLY = 0x00000001, + NTFS_MNT_MAY_RDONLY = 0x02000000, /* Allow fallback to ro */ NTFS_MNT_FORENSIC = 0x04000000, /* No modification during * mount. */ NTFS_MNT_EXCLUSIVE = 0x08000000, diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c index 916f1c02..4861d2f8 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -97,6 +97,11 @@ static const char *hibernated_volume_msg = "Windows fully (no hibernation or fast restarting), or mount the volume\n" "read-only with the 'ro' mount option.\n"; +static const char *fallback_readonly_msg = +"Falling back to read-only mount because the NTFS partition is in an\n" +"unsafe state. Please resume and shutdown Windows fully (no hibernation\n" +"or fast restarting.)\n"; + static const char *unclean_journal_msg = "Write access is denied because the disk wasn't safely powered\n" "off and the 'norecover' mount option was specified.\n"; @@ -914,7 +919,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) int i, j, eo; unsigned int k; u32 u; + BOOL need_fallback_ro; + need_fallback_ro = FALSE; vol = ntfs_volume_startup(dev, flags); if (!vol) return NULL; @@ -1233,20 +1240,35 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) */ if (!(flags & (NTFS_MNT_RDONLY | NTFS_MNT_FORENSIC))) { if (!(flags & NTFS_MNT_IGNORE_HIBERFILE) && - ntfs_volume_check_hiberfile(vol, 1) < 0) - goto error_exit; + ntfs_volume_check_hiberfile(vol, 1) < 0) { + if (flags & NTFS_MNT_MAY_RDONLY) + need_fallback_ro = TRUE; + else + goto error_exit; + } if (ntfs_volume_check_logfile(vol) < 0) { /* Always reject cached metadata for now */ - if (!(flags & NTFS_MNT_RECOVER) || (errno == EPERM)) - goto error_exit; - ntfs_log_info("The file system wasn't safely " - "closed on Windows. Fixing.\n"); - if (ntfs_logfile_reset(vol)) - goto error_exit; + if (!(flags & NTFS_MNT_RECOVER) || (errno == EPERM)) { + if (flags & NTFS_MNT_MAY_RDONLY) + need_fallback_ro = TRUE; + else + goto error_exit; + } else { + ntfs_log_info("The file system wasn't safely " + "closed on Windows. Fixing.\n"); + if (ntfs_logfile_reset(vol)) + goto error_exit; + } } /* make $TXF_DATA resident if present on the root directory */ - if (fix_txf_data(vol)) - goto error_exit; + if (!(flags & NTFS_MNT_RDONLY) && !need_fallback_ro) { + if (fix_txf_data(vol)) + goto error_exit; + } + } + if (need_fallback_ro) { + NVolSetReadOnly(vol); + ntfs_log_error("%s", fallback_readonly_msg); } return vol; diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 899586c1..683ac0c6 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -3940,6 +3940,8 @@ static int ntfs_open(const char *device) flags |= NTFS_MNT_EXCLUSIVE; if (ctx->ro) flags |= NTFS_MNT_RDONLY; + else + flags |= NTFS_MNT_MAY_RDONLY; if (ctx->recover) flags |= NTFS_MNT_RECOVER; if (ctx->hiberfile) diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index e3a23e58..5b19b1dc 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -3744,6 +3744,8 @@ static int ntfs_open(const char *device) flags |= NTFS_MNT_EXCLUSIVE; if (ctx->ro) flags |= NTFS_MNT_RDONLY; + else + flags |= NTFS_MNT_MAY_RDONLY; if (ctx->recover) flags |= NTFS_MNT_RECOVER; if (ctx->hiberfile) From 6c768f215d1f308cd8ad988942838d51e0357312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 09:57:59 +0200 Subject: [PATCH 09/86] Used a more portable way to force alignment in security.h Defining an array of zero elements does not force alignment on some CPUs, insert a filler. --- include/ntfs-3g/security.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ntfs-3g/security.h b/include/ntfs-3g/security.h index d28bc89b..b5c6375e 100644 --- a/include/ntfs-3g/security.h +++ b/include/ntfs-3g/security.h @@ -173,7 +173,7 @@ struct POSIX_SECURITY { int defcnt; int firstdef; u16 tagsset; - s32 alignment[0]; + u16 filler; struct POSIX_ACL acl; } ; From e8170f588f25e96c08b5f319ab02079bddfb0926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:02:23 +0200 Subject: [PATCH 10/86] Fixed the maximum size of an ACL Define the maximum size of an ACL as results from the maximum number of sub-authorities defined in layout.h --- include/ntfs-3g/acls.h | 5 +++-- libntfs-3g/acls.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/ntfs-3g/acls.h b/include/ntfs-3g/acls.h index a91eda7c..6506f78e 100644 --- a/include/ntfs-3g/acls.h +++ b/include/ntfs-3g/acls.h @@ -102,10 +102,11 @@ #define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */ /* - * A type large enough to hold any SID + * Maximum SID size and a type large enough to hold it */ -typedef char BIGSID[40]; +#define MAX_SID_SIZE (8 + SID_MAX_SUB_AUTHORITIES*4) +typedef char BIGSID[MAX_SID_SIZE]; /* * Struct to hold the input mapping file diff --git a/libntfs-3g/acls.c b/libntfs-3g/acls.c index 1df88aa6..524cc83c 100644 --- a/libntfs-3g/acls.c +++ b/libntfs-3g/acls.c @@ -2790,10 +2790,10 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[], for (k=0; kacccnt; k++) { if ((pxdesc->acl.ace[k].tag == POSIX_ACL_USER) || (pxdesc->acl.ace[k].tag == POSIX_ACL_GROUP)) - newattrsz += 3*40; /* fixme : maximum size */ + newattrsz += 3*MAX_SID_SIZE; } /* account for default ACE's */ - newattrsz += 2*40*pxdesc->defcnt; /* fixme : maximum size */ + newattrsz += 2*MAX_SID_SIZE*pxdesc->defcnt; newattr = (char*)ntfs_malloc(newattrsz); if (newattr) { /* build the main header part */ From 31430ae01a99db0107ff6d198050ed7d83371582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:08:01 +0200 Subject: [PATCH 11/86] Returned an error code for an exclusive access violation on Windows Translate to Windows error code STATUS_SHARING_VIOLATION to Unix error code EBUSY. --- libntfs-3g/win32_io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libntfs-3g/win32_io.c b/libntfs-3g/win32_io.c index c4c09d7d..e5cfb640 100644 --- a/libntfs-3g/win32_io.c +++ b/libntfs-3g/win32_io.c @@ -150,6 +150,7 @@ enum { /* see http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx * STATUS_FILE_NOT_FOUND = 0xC0000028, STATUS_OBJECT_NAME_INVALID = 0xC0000033, STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034, + STATUS_SHARING_VIOLATION = 0xC0000043, STATUS_INVALID_PARAMETER_1 = 0xC00000EF, STATUS_IO_DEVICE_ERROR = 0xC0000185, STATUS_GUARD_PAGE_VIOLATION = 0x80000001 @@ -354,6 +355,8 @@ static int ntfs_ntstatus_to_errno(NTSTATUS status) case STATUS_IO_DEVICE_ERROR : case STATUS_END_OF_FILE : return (EIO); + case STATUS_SHARING_VIOLATION : + return (EBUSY); default: /* generic message */ return ENOMSG; From 6cb8913967cc2e376926d38403975d182fb09af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:11:08 +0200 Subject: [PATCH 12/86] Translated directory separators when running ntfscluster on Windows Use \ as a directory separator when running on Windows. --- ntfsprogs/ntfscluster.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ntfsprogs/ntfscluster.c b/ntfsprogs/ntfscluster.c index 6a7e7289..1f171634 100644 --- a/ntfsprogs/ntfscluster.c +++ b/ntfsprogs/ntfscluster.c @@ -486,6 +486,9 @@ int main(int argc, char *argv[]) struct match m; int res; int result = 1; +#ifdef HAVE_WINDOWS_H + char *unix_name; +#endif ntfs_log_set_handler(ntfs_log_handler_outerr); @@ -521,7 +524,17 @@ int main(int argc, char *argv[]) result = cluster_find(vol, opts.range_begin, opts.range_end, (cluster_cb*)&print_match, NULL); break; case act_file: +#ifdef HAVE_WINDOWS_H + unix_name = ntfs_utils_unix_path(opts.filename); + ino = 0; + if (unix_name) { + ino = ntfs_pathname_to_inode(vol, NULL, + unix_name); + free(unix_name); + } +#else ino = ntfs_pathname_to_inode(vol, NULL, opts.filename); +#endif if (ino) result = dump_file(vol, ino); break; From 88451c80696f1ea6b0aa3822a9a3969f6bcae41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:17:27 +0200 Subject: [PATCH 13/86] Made a full check for whether a user extended attribute is allowed User extended attributes should only be set on files and directories, not on symlinks, sockets, devices, etc. For safety they are also forbidden on metadata files, but should be allowed on the root directory. For files based on reparse points, requests are made to the plugin to determine the type. --- include/ntfs-3g/dir.h | 1 + libntfs-3g/dir.c | 12 ++++++--- src/lowntfs-3g.c | 12 ++++----- src/ntfs-3g.c | 12 ++++----- src/ntfs-3g_common.c | 58 +++++++++++++++++++++++++++++++++++++++++++ src/ntfs-3g_common.h | 1 + 6 files changed, 81 insertions(+), 15 deletions(-) diff --git a/include/ntfs-3g/dir.h b/include/ntfs-3g/dir.h index a99c1ae0..e6a2c3b1 100644 --- a/include/ntfs-3g/dir.h +++ b/include/ntfs-3g/dir.h @@ -109,6 +109,7 @@ extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, void *dirent, ntfs_filldir_t filldir); ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni); +u32 ntfs_interix_types(ntfs_inode *ni); int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, char *value, size_t size); diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index b6447ff4..e4d48ed0 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -875,7 +875,7 @@ typedef enum { * and most metadata files have such similar patters. */ -static u32 ntfs_interix_types(ntfs_inode *ni) +u32 ntfs_interix_types(ntfs_inode *ni) { ntfs_attr *na; u32 dt_type; @@ -884,8 +884,14 @@ static u32 ntfs_interix_types(ntfs_inode *ni) dt_type = NTFS_DT_UNKNOWN; na = ntfs_attr_open(ni, AT_DATA, NULL, 0); if (na) { - /* Unrecognized patterns (eg HID + SYST) are plain files */ - dt_type = NTFS_DT_REG; + /* + * Unrecognized patterns (eg HID + SYST for metadata) + * are plain files or directories + */ + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + dt_type = NTFS_DT_DIR; + else + dt_type = NTFS_DT_REG; if (na->data_size <= 1) { if (!(ni->flags & FILE_ATTR_HIDDEN)) dt_type = (na->data_size ? diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 683ac0c6..80c224f8 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -3165,7 +3165,7 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) goto out; } /* Return with no result for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) + if (!user_xattrs_allowed(ctx, ni)) goto exit; /* otherwise file must be readable */ #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) @@ -3314,7 +3314,7 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, goto out; } /* Return with no result for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -ENODATA; goto exit; } @@ -3511,7 +3511,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, break; default : /* User xattr not allowed for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3524,7 +3524,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, #else /* User xattr not allowed for symlinks, fifo, etc. */ if ((namespace == XATTRNS_USER) - && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { + && !user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3756,7 +3756,7 @@ static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *na break; default : /* User xattr not allowed for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3769,7 +3769,7 @@ static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *na #else /* User xattr not allowed for symlinks, fifo, etc. */ if ((namespace == XATTRNS_USER) - && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { + && !user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 5b19b1dc..4b4ec363 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -2946,7 +2946,7 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size) if (!ni) return -errno; /* Return with no result for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) + if (!user_xattrs_allowed(ctx, ni)) goto exit; /* otherwise file must be readable */ #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) @@ -3148,7 +3148,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, if (!ni) return -errno; /* Return with no result for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -ENODATA; goto exit; } @@ -3324,7 +3324,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, break; default : /* User xattr not allowed for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3337,7 +3337,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, #else /* User xattr not allowed for symlinks, fifo, etc. */ if ((namespace == XATTRNS_USER) - && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { + && !user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3561,7 +3561,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) break; default : /* User xattr not allowed for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3574,7 +3574,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) #else /* User xattr not allowed for symlinks, fifo, etc. */ if ((namespace == XATTRNS_USER) - && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { + && !user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } diff --git a/src/ntfs-3g_common.c b/src/ntfs-3g_common.c index 425e8102..29fa42c0 100644 --- a/src/ntfs-3g_common.c +++ b/src/ntfs-3g_common.c @@ -48,6 +48,7 @@ #include #include "inode.h" +#include "dir.h" #include "security.h" #include "xattrs.h" #include "reparse.h" @@ -862,3 +863,60 @@ void close_reparse_plugins(ntfs_fuse_context_t *ctx) } #endif /* PLUGINS_DISABLED */ + +#ifdef HAVE_SETXATTR + +/* + * Check whether a user xattr is allowed + * + * The inode must be a plain file or a directory. The only allowed + * metadata file is the root directory (useful for MacOSX and hopefully + * does not harm Windows). + */ + +BOOL user_xattrs_allowed(ntfs_fuse_context_t *ctx, ntfs_inode *ni) +{ + u32 dt_type; + BOOL res; + + /* Quick return for common cases and root */ + if (!(ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) + || (ni->mft_no == FILE_root)) + res = TRUE; + else { + /* Reparse point depends on kind, see plugin */ + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + struct stat stbuf; + REPARSE_POINT *reparse; + const plugin_operations_t *ops; + + res = FALSE; /* default for error cases */ + ops = select_reparse_plugin(ctx, ni, &reparse); + if (ops) { + if (ops->getattr + && !ops->getattr(ni,reparse,&stbuf)) { + res = S_ISREG(stbuf.st_mode) + || S_ISDIR(stbuf.st_mode); + } + free(reparse); +#else /* PLUGINS_DISABLED */ + res = FALSE; /* mountpoints, symlinks, ... */ +#endif /* PLUGINS_DISABLED */ + } + } else { + /* Metadata */ + if (ni->mft_no < FILE_first_user) + res = FALSE; + else { + /* Interix types */ + dt_type = ntfs_interix_types(ni); + res = (dt_type == NTFS_DT_REG) + || (dt_type == NTFS_DT_DIR); + } + } + } + return (res); +} + +#endif /* HAVE_SETXATTR */ diff --git a/src/ntfs-3g_common.h b/src/ntfs-3g_common.h index 22452321..e9026576 100644 --- a/src/ntfs-3g_common.h +++ b/src/ntfs-3g_common.h @@ -208,6 +208,7 @@ const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx, ntfs_inode *ni, REPARSE_POINT **reparse); int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag, const plugin_operations_t *ops, void *handle); +BOOL user_xattrs_allowed(ntfs_fuse_context_t *ctx, ntfs_inode *ni); #endif /* PLUGINS_DISABLED */ From 71b03fbd163e45a90e5110350b38d89c6af7dd23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:26:46 +0200 Subject: [PATCH 14/86] Redefined ntfsrecover enums as little-endian values Rather than cpu-endian values, use little-endian ones in ntfsrecover for similarity with layout.h --- ntfsprogs/ntfsrecover.c | 16 ++++++------ ntfsprogs/ntfsrecover.h | 57 ++++++++++++++++++++++++++++------------- ntfsprogs/playlog.c | 20 +++++++-------- 3 files changed, 56 insertions(+), 37 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index aae96adf..dbcf977a 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -832,7 +832,7 @@ static BOOL likelyop(const struct LOG_RECORD *logr) { BOOL likely; - switch (le32_to_cpu(logr->record_type)) { + switch (logr->record_type) { case LOG_STANDARD : /* standard record */ /* Operations in range 0..LastAction-1, can be both null */ likely = ((unsigned int)le16_to_cpu(logr->redo_operation) @@ -1845,8 +1845,8 @@ static void detaillogr(CONTEXT *ctx, const struct LOG_RECORD *logr) unsigned int listsize; BOOL onmft; - switch (le32_to_cpu(logr->record_type)) { - case 1 : + switch (logr->record_type) { + case LOG_STANDARD : onmft = logr->cluster_index || acts_on_mft(le16_to_cpu(logr->redo_operation)) || acts_on_mft(le16_to_cpu(logr->undo_operation)); @@ -2068,7 +2068,7 @@ static void detaillogr(CONTEXT *ctx, const struct LOG_RECORD *logr) printf("* undo data overflows from record\n"); } break; - case 2 : + case LOG_CHECKPOINT : printf("---> checkpoint record\n"); printf("redo_operation %04x %s\n", (int)le16_to_cpu(logr->redo_operation), @@ -2117,8 +2117,8 @@ BOOL within_lcn_range(const struct LOG_RECORD *logr) BOOL within; within = FALSE; - switch (le32_to_cpu(logr->record_type)) { - case 1 : + switch (logr->record_type) { + case LOG_STANDARD : for (i=0; ilcns_to_follow); i++) { lcn = MREF(le64_to_cpu(logr->lcn_list[i])); if ((lcn >= firstlcn) && (lcn <= lastlcn)) @@ -2166,7 +2166,7 @@ static void showlogr(CONTEXT *ctx, int k, const struct LOG_RECORD *logr) if (optt) { const char *state; - if (logr->record_type == const_cpu_to_le32(2)) + if (logr->record_type == LOG_CHECKPOINT) state = "--checkpoint--"; else state = commitment(sle64_to_cpu(logr->this_lsn)); @@ -2290,7 +2290,7 @@ static TRISTATE enqueue_action(CONTEXT *ctx, const struct LOG_RECORD *logr, err = 0; state = T_OK; if ((optp || optu) - && (logr->record_type == const_cpu_to_le32(2))) { + && (logr->record_type == LOG_CHECKPOINT)) { /* if chkp process queue, and increment count */ playedactions++; if (playedactions <= playcount) { diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index 5da42c66..692aa178 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -40,16 +40,29 @@ #define feedle32(p,x) (*(const le32*)((const char*)(p) + (x))) #define feedle64(p,x) (*(const le64*)((const char*)(p) + (x))) -enum LOG_RECORD_TYPE { - LOG_STANDARD = 1, - LOG_CHECKPOINT = 2 -} ; +/* + * LOG_RECORD_TYPE : types of log records + */ - /* These flags were introduced in Vista in field attribute_flags */ -enum ATTRIBUTE_FLAGS { - ACTS_ON_MFT = 2, - ACTS_ON_INDX = 8 +enum { + LOG_STANDARD = const_cpu_to_le32(1), + LOG_CHECKPOINT = const_cpu_to_le32(2), + LOG_RECORD_TYPE_PLACE_HOLDER = 0xffffffffU } ; +typedef le32 LOG_RECORD_TYPE; + +/* + * ATTRIBUTE_FLAGS : flags describing the kind of NTFS record + * is being updated. + * These flags were introduced in Vista, only two flags are known? + */ + +enum { + ACTS_ON_MFT = const_cpu_to_le16(2), + ACTS_ON_INDX = const_cpu_to_le16(8), + ATTRIBUTE_FLAGS_PLACE_HOLDER = 0xffff, +} ; +typedef le16 ATTRIBUTE_FLAGS; enum ACTIONS { Noop, /* 0 */ @@ -93,14 +106,22 @@ enum ACTIONS { LastAction /* 38 */ } ; - /* Flags for field log_record_flags, their meaning is unclear */ -enum RECORD_FLAGS { - RECORD_UNKNOWN = 1, - /* The flags below were introduced in Windows 10 */ - RECORD_DELETING = 2, - RECORD_ADDING = 4 -} ; -typedef le16 LOG_RECORD_FLAGS; +/** + * enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records. + * + * Some flags describe what kind of update is being logged. + * + * (Or is it log record pages?) + */ +typedef enum { + LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */ + /* The flags below were introduced in Windows 10 */ + LOG_RECORD_DELETING = const_cpu_to_le16(0x0002), + LOG_RECORD_ADDING = const_cpu_to_le16(0x0004), + LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff, + /* This has nothing to do with the log record. It is only so + gcc knows to make the flags 16-bit. */ +} __attribute__((__packed__)) LOG_RECORD_FLAGS; #define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff) #define RESTART_VOLUME_IS_CLEAN const_cpu_to_le16(0x0002) @@ -200,7 +221,7 @@ typedef struct LOG_RECORD { /* size 80 */ le16 seq_number; le16 client_index; } __attribute__((__packed__)) client_id; - le32 record_type; + LOG_RECORD_TYPE record_type; le32 transaction_id; LOG_RECORD_FLAGS log_record_flags; le16 reserved1[3]; @@ -217,7 +238,7 @@ typedef struct LOG_RECORD { /* size 80 */ le16 record_offset; le16 attribute_offset; le16 cluster_index; - le16 attribute_flags; + ATTRIBUTE_FLAGS attribute_flags; le32 target_vcn; le32 reserved3; le64 lcn_list[0]; diff --git a/ntfsprogs/playlog.c b/ntfsprogs/playlog.c index d8ba333d..83d63071 100644 --- a/ntfsprogs/playlog.c +++ b/ntfsprogs/playlog.c @@ -3991,13 +3991,11 @@ static enum ACTION_KIND get_action_kind(const struct ACTION_RECORD *action) * the action was defined by Win10 (or subsequent). */ if (action->record.log_record_flags - & const_cpu_to_le16(RECORD_DELETING | RECORD_ADDING)) { - if (action->record.attribute_flags - & const_cpu_to_le16(ACTS_ON_INDX)) + & (LOG_RECORD_DELETING | LOG_RECORD_ADDING)) { + if (action->record.attribute_flags & ACTS_ON_INDX) kind = ON_INDX; else - if (action->record.attribute_flags - & const_cpu_to_le16(ACTS_ON_MFT)) + if (action->record.attribute_flags & ACTS_ON_MFT) kind = ON_MFT; else kind = ON_RAW; @@ -4325,7 +4323,7 @@ static int play_one_redo(ntfs_volume *vol, const struct ACTION_RECORD *action) case ON_MFT : /* the check below cannot be used on WinXP -if (!(action->record.attribute_flags & const_cpu_to_le16(ACTS_ON_MFT))) +if (!(action->record.attribute_flags & ACTS_ON_MFT)) printf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num); */ /* Check whether data is to be discarded */ @@ -4366,7 +4364,7 @@ printf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num) case ON_INDX : /* the check below cannot be used on WinXP -if (!(action->record.attribute_flags & const_cpu_to_le16(ACTS_ON_INDX))) +if (!(action->record.attribute_flags & ACTS_ON_INDX)) printf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num); */ xsize = vol->indx_record_size; @@ -4407,7 +4405,7 @@ printf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num break; case ON_RAW : if (action->record.attribute_flags - & (const_cpu_to_le16(ACTS_ON_INDX | ACTS_ON_MFT))) { + & (ACTS_ON_INDX | ACTS_ON_MFT)) { printf("** Error : action %s on MFT" " or INDX\n", actionname(rop)); @@ -4707,7 +4705,7 @@ static int play_one_undo(ntfs_volume *vol, const struct ACTION_RECORD *action) case ON_MFT : /* the check below cannot be used on WinXP -if (!(action->record.attribute_flags & const_cpu_to_le16(ACTS_ON_MFT))) +if (!(action->record.attribute_flags & ACTS_ON_MFT)) printf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num); */ buffer = read_protected(vol, &action->record, mftrecsz, TRUE); @@ -4746,7 +4744,7 @@ printf("record lsn 0x%llx is %s than action %d lsn 0x%llx\n", case ON_INDX : /* the check below cannot be used on WinXP -if (!(action->record.attribute_flags & const_cpu_to_le16(ACTS_ON_INDX))) +if (!(action->record.attribute_flags & ACTS_ON_INDX)) printf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num); */ xsize = vol->indx_record_size; @@ -4797,7 +4795,7 @@ printf("index lsn 0x%llx is %s than action %d lsn 0x%llx\n", break; case ON_RAW : if (action->record.attribute_flags - & (const_cpu_to_le16(ACTS_ON_INDX | ACTS_ON_MFT))) { + & (ACTS_ON_INDX | ACTS_ON_MFT)) { printf("** Error : action %s on MFT or INDX\n", actionname(rop)); err = 1; From 2ab8bb509afe99e66ce28a691428def40fffa1f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:32:39 +0200 Subject: [PATCH 15/86] Typedef'ed old structs in ntfsrecover the same way as in logfile.h Prepare merging ntfsrecover.h into logfile.h by declaring duplicated structs the same way --- ntfsprogs/ntfsrecover.c | 196 ++++++++++++++++++++-------------------- ntfsprogs/ntfsrecover.h | 32 +++---- ntfsprogs/playlog.c | 12 +-- 3 files changed, 120 insertions(+), 120 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index dbcf977a..798a0d0f 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -114,9 +114,9 @@ typedef struct { typedef enum { T_OK, T_ERR, T_DONE } TRISTATE; -struct RESTART_PAGE_HEADER log_header; -struct RESTART_AREA restart; -struct RESTART_CLIENT client; +RESTART_PAGE_HEADER log_header; +RESTART_AREA restart; +LOG_CLIENT_RECORD client; u32 clustersz = 0; int clusterbits; u32 blocksz; @@ -206,7 +206,7 @@ static s64 loclogblk(CONTEXT *ctx, unsigned int blk) static int replaceusa(struct BUFFER *buffer, unsigned int lth) { char *buf; - struct RECORD_PAGE_HEADER *record; + RECORD_PAGE_HEADER *record; unsigned int j; BOOL err; unsigned int used; @@ -358,7 +358,7 @@ static const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num) 1, ctx->file) == 1); if (got) { char *data = buffer->block.data; - buffer->headsz = sizeof(struct RECORD_PAGE_HEADER) + buffer->headsz = sizeof(RECORD_PAGE_HEADER) + ((2*getle16(data,6) - 1) | 7) + 1; buffer->safe = !replaceusa(buffer, blocksz); } else { @@ -794,7 +794,7 @@ static BOOL acts_on_mft(int op) return (onmft); } -u32 get_undo_offset(const struct LOG_RECORD *logr) +u32 get_undo_offset(const LOG_RECORD *logr) { u32 offset; @@ -805,7 +805,7 @@ u32 get_undo_offset(const struct LOG_RECORD *logr) return (offset); } -u32 get_redo_offset(const struct LOG_RECORD *logr) +u32 get_redo_offset(const LOG_RECORD *logr) { u32 offset; @@ -816,7 +816,7 @@ u32 get_redo_offset(const struct LOG_RECORD *logr) return (offset); } -u32 get_extra_offset(const struct LOG_RECORD *logr) +u32 get_extra_offset(const LOG_RECORD *logr) { u32 uoffset; u32 roffset; @@ -828,7 +828,7 @@ u32 get_extra_offset(const struct LOG_RECORD *logr) return ((((uoffset > roffset ? uoffset : roffset) - 1) | 7) + 1); } -static BOOL likelyop(const struct LOG_RECORD *logr) +static BOOL likelyop(const LOG_RECORD *logr) { BOOL likely; @@ -914,7 +914,7 @@ static BOOL likelyop(const struct LOG_RECORD *logr) static u16 searchlikely(const struct BUFFER *buf) { - const struct LOG_RECORD *logr; + const LOG_RECORD *logr; const char *data; u16 k; @@ -922,11 +922,11 @@ static u16 searchlikely(const struct BUFFER *buf) printf("** Error : searchlikely() used for syncing\n"); data = buf->block.data; k = buf->headsz; - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; if (!likelyop(logr)) { do { k += 8; - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; } while ((k <= (blocksz - LOG_RECORD_HEAD_SZ)) && !likelyop(logr)); if (k > (blocksz - LOG_RECORD_HEAD_SZ)) @@ -954,9 +954,9 @@ static u16 searchlikely(const struct BUFFER *buf) static u16 firstrecord(int skipped, const struct BUFFER *buf, const struct BUFFER *prevbuf) { - const struct RECORD_PAGE_HEADER *rph; - const struct RECORD_PAGE_HEADER *prevrph; - const struct LOG_RECORD *logr; + const RECORD_PAGE_HEADER *rph; + const RECORD_PAGE_HEADER *prevrph; + const LOG_RECORD *logr; const char *data; const char *prevdata; u16 k; @@ -978,7 +978,7 @@ static u16 firstrecord(int skipped, const struct BUFFER *buf, k = 0; /* Minimal size is apparently 48 : offset of redo_operation */ if (k && ((blocksz - k) >= LOG_RECORD_HEAD_SZ)) { - logr = (const struct LOG_RECORD*)&prevdata[k]; + logr = (const LOG_RECORD*)&prevdata[k]; if (!logr->client_data_length) { /* * Sometimes the end of record is free space. @@ -1051,7 +1051,7 @@ static u16 firstrecord(int skipped, const struct BUFFER *buf, * try to find a starting record. */ if (k && prevbuf && (prevbuf->num > buf->num)) { - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; /* Accept reaching the end with no record beginning */ if ((k != le16_to_cpu(rph->next_record_offset)) && !likelyop(logr)) { @@ -1081,7 +1081,7 @@ static const struct BUFFER *findprevious(CONTEXT *ctx, const struct BUFFER *buf) { const struct BUFFER *prevbuf; const struct BUFFER *savebuf; - const struct RECORD_PAGE_HEADER *rph; + const RECORD_PAGE_HEADER *rph; int skipped; int prevblk; BOOL prevmiddle; @@ -1148,8 +1148,8 @@ static const struct BUFFER *findprevious(CONTEXT *ctx, const struct BUFFER *buf) void copy_attribute(struct ATTR *pa, const char *buf, int length) { - const struct ATTR_NEW *panew; - struct ATTR_OLD old_aligned; + const ATTR_NEW *panew; + ATTR_OLD old_aligned; if (pa) { switch (length) { @@ -1176,7 +1176,7 @@ void copy_attribute(struct ATTR *pa, const char *buf, int length) static int refresh_attributes(const struct ACTION_RECORD *firstaction) { const struct ACTION_RECORD *action; - const struct LOG_RECORD *logr; + const LOG_RECORD *logr; struct ATTR *pa; const char *buf; u32 extra; @@ -1267,7 +1267,7 @@ static int refresh_attributes(const struct ACTION_RECORD *firstaction) * Display a fixup */ -static void fixup(CONTEXT *ctx, const struct LOG_RECORD *logr, const char *buf, +static void fixup(CONTEXT *ctx, const LOG_RECORD *logr, const char *buf, BOOL redo) { struct ATTR *pa; @@ -1832,7 +1832,7 @@ static void fixup(CONTEXT *ctx, const struct LOG_RECORD *logr, const char *buf, } } -static void detaillogr(CONTEXT *ctx, const struct LOG_RECORD *logr) +static void detaillogr(CONTEXT *ctx, const LOG_RECORD *logr) { u64 lcn; u64 baselcn; @@ -2090,7 +2090,7 @@ static void detaillogr(CONTEXT *ctx, const struct LOG_RECORD *logr) (long long)sle64_to_cpu(logr->dirty_pages_lsn)); listsize = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ - - offsetof(struct LOG_RECORD, unknown_list); + - offsetof(LOG_RECORD, unknown_list); if (listsize > 8*SHOWLISTS) listsize = 8*SHOWLISTS; for (i=0; 8*iblock.data; - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ; blkheadsz = buf->headsz; if (nextbuf && (blk >= BASEBLKS)) { @@ -2457,7 +2457,7 @@ static u16 overlapshow(CONTEXT *ctx, u16 k, u32 blk, const struct BUFFER *buf, memcpy(&fullrec[space], nextdata + blkheadsz, size - space); - likely = likelyop((struct LOG_RECORD*)fullrec); + likely = likelyop((LOG_RECORD*)fullrec); actionnum++; if (optv) { printf("\nOverlapping record %u at 0x%x" @@ -2470,7 +2470,7 @@ static u16 overlapshow(CONTEXT *ctx, u16 k, u32 blk, const struct BUFFER *buf, } if (likely) showlogr(ctx, k, - (struct LOG_RECORD*)fullrec); + (LOG_RECORD*)fullrec); else printf("** Skipping unlikely" " overlapping record\n"); @@ -2523,7 +2523,7 @@ static u16 overlapshow(CONTEXT *ctx, u16 k, u32 blk, const struct BUFFER *buf, size - pos); else likely = FALSE; - if (!likelyop((struct LOG_RECORD*)fullrec)) + if (!likelyop((LOG_RECORD*)fullrec)) likely = FALSE; actionnum++; if (optv) { @@ -2537,7 +2537,7 @@ static u16 overlapshow(CONTEXT *ctx, u16 k, u32 blk, const struct BUFFER *buf, } if (likely) showlogr(ctx, k, - (struct LOG_RECORD*)fullrec); + (LOG_RECORD*)fullrec); else printf("** Skipping unlikely" " overlapping record\n"); @@ -2589,8 +2589,8 @@ static u16 overlapshow(CONTEXT *ctx, u16 k, u32 blk, const struct BUFFER *buf, static u16 forward_rcrd(CONTEXT *ctx, u32 blk, u16 pos, const struct BUFFER *buf, const struct BUFFER *nextbuf) { - const struct RECORD_PAGE_HEADER *rph; - const struct LOG_RECORD *logr; + const RECORD_PAGE_HEADER *rph; + const LOG_RECORD *logr; const char *data; u16 k; u16 endoff; @@ -2605,19 +2605,19 @@ static u16 forward_rcrd(CONTEXT *ctx, u32 blk, u16 pos, k = ((pos - 1) | 7) + 1; } // TODO check bad start > blocksz - 48 - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; stop = FALSE; if (!likelyop(logr)) { if (optv) printf("* Bad start 0x%x for block %d\n", (int)pos,(int)blk); k = searchlikely(buf); - if ((k + sizeof(struct LOG_RECORD)) > blocksz) { + if ((k + sizeof(LOG_RECORD)) > blocksz) { printf("No likely full record in block %lu\n", (unsigned long)blk); /* there can be a partial one */ k = le16_to_cpu(rph->next_record_offset); - if ((k < (u16)sizeof(struct RECORD_PAGE_HEADER)) + if ((k < (u16)sizeof(RECORD_PAGE_HEADER)) || ((blocksz - k) < LOG_RECORD_HEAD_SZ)) stop = TRUE; } else { @@ -2629,7 +2629,7 @@ static u16 forward_rcrd(CONTEXT *ctx, u32 blk, u16 pos, while (!stop) { s32 size; - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ; if ((size < MINRECSIZE) @@ -2684,10 +2684,10 @@ static u16 forward_rcrd(CONTEXT *ctx, u32 blk, u16 pos, * Display a restart page */ -static void showrest(const struct RESTART_PAGE_HEADER *rest) +static void showrest(const RESTART_PAGE_HEADER *rest) { - const struct RESTART_AREA *resa; - const struct RESTART_CLIENT *rcli; + const RESTART_AREA *resa; + const LOG_CLIENT_RECORD *rcli; const char *data; data = (const char*)rest; @@ -2720,7 +2720,7 @@ static void showrest(const struct RESTART_PAGE_HEADER *rest) printf(" chkdsk %016llx\n", (long long)sle64_to_cpu(rest->chkdsk_lsn)); } - resa = (const struct RESTART_AREA*) + resa = (const RESTART_AREA*) &data[le16_to_cpu(rest->restart_offset)]; if (optv) { printf("current_lsn %016llx\n", @@ -2756,7 +2756,7 @@ static void showrest(const struct RESTART_PAGE_HEADER *rest) (long long)sle64_to_cpu(resa->current_lsn)); } - rcli = (const struct RESTART_CLIENT*) + rcli = (const LOG_CLIENT_RECORD*) &data[le16_to_cpu(rest->restart_offset) + le16_to_cpu(resa->client_array_offset)]; if (optv) { @@ -2791,10 +2791,10 @@ static void showrest(const struct RESTART_PAGE_HEADER *rest) } static BOOL dorest(CONTEXT *ctx, unsigned long blk, - const struct RESTART_PAGE_HEADER *rph, BOOL initial) + const RESTART_PAGE_HEADER *rph, BOOL initial) { - const struct RESTART_AREA *resa; - const struct RESTART_CLIENT *rcli; + const RESTART_AREA *resa; + const LOG_CLIENT_RECORD *rcli; const char *data; s64 diff; int offs; @@ -2804,8 +2804,8 @@ static BOOL dorest(CONTEXT *ctx, unsigned long blk, data = (const char*)rph; offs = le16_to_cpu(rph->restart_offset); - resa = (const struct RESTART_AREA*)&data[offs]; - rcli = (const struct RESTART_CLIENT*)&data[offs + resa = (const RESTART_AREA*)&data[offs]; + rcli = (const LOG_CLIENT_RECORD*)&data[offs + le16_to_cpu(resa->client_array_offset)]; if (initial) { /* Information from block initially found best */ @@ -2813,13 +2813,13 @@ static BOOL dorest(CONTEXT *ctx, unsigned long blk, committed_lsn = sle64_to_cpu(rcli->client_restart_lsn); synced_lsn = sle64_to_cpu(rcli->oldest_lsn); memcpy(&log_header, rph, - sizeof(struct RESTART_PAGE_HEADER)); + sizeof(RESTART_PAGE_HEADER)); offs = le16_to_cpu(log_header.restart_offset); memcpy(&restart, &data[offs], - sizeof(struct RESTART_AREA)); + sizeof(RESTART_AREA)); offs += le16_to_cpu(restart.client_array_offset); memcpy(&client, &data[offs], - sizeof(struct RESTART_CLIENT)); + sizeof(LOG_CLIENT_RECORD)); dirty = !(resa->flags & RESTART_VOLUME_IS_CLEAN); if (optv || optt) printf("* Using initial restart page," @@ -2859,13 +2859,13 @@ static BOOL dorest(CONTEXT *ctx, unsigned long blk, synced_lsn = sle64_to_cpu(rcli->oldest_lsn); latest_lsn = sle64_to_cpu(resa->current_lsn); memcpy(&log_header, rph, - sizeof(struct RESTART_PAGE_HEADER)); + sizeof(RESTART_PAGE_HEADER)); offs = le16_to_cpu(log_header.restart_offset); memcpy(&restart, &data[offs], - sizeof(struct RESTART_AREA)); + sizeof(RESTART_AREA)); offs += le16_to_cpu(restart.client_array_offset); memcpy(&client, &data[offs], - sizeof(struct RESTART_CLIENT)); + sizeof(LOG_CLIENT_RECORD)); dirty = !(resa->flags & RESTART_VOLUME_IS_CLEAN); if (optv || optt) printf("* Using %s restart page," @@ -2898,9 +2898,9 @@ static const struct BUFFER *read_restart(CONTEXT *ctx) bad = FALSE; if (ctx->vol) { - struct RESTART_PAGE_HEADER *rph; + RESTART_PAGE_HEADER *rph; - rph = (struct RESTART_PAGE_HEADER*)NULL; + rph = (RESTART_PAGE_HEADER*)NULL; /* Full mode : use the restart page selected by the library */ if (ntfs_check_logfile(log_na, &rph)) { /* rph is left unchanged for a wiped out log file */ @@ -2976,13 +2976,13 @@ static int reset_logfile(CONTEXT *ctx __attribute__((unused))) restart.flags |= RESTART_VOLUME_IS_CLEAN; client.oldest_lsn = cpu_to_sle64(restart_lsn); memcpy(buffer, &log_header, - sizeof(struct RESTART_PAGE_HEADER)); + sizeof(RESTART_PAGE_HEADER)); off = le16_to_cpu(log_header.restart_offset); memcpy(&buffer[off], &restart, - sizeof(struct RESTART_AREA)); + sizeof(RESTART_AREA)); off += le16_to_cpu(restart.client_array_offset); memcpy(&buffer[off], &client, - sizeof(struct RESTART_CLIENT)); + sizeof(LOG_CLIENT_RECORD)); if (!ntfs_mst_pre_write_fixup((NTFS_RECORD*)buffer, blocksz) && (ntfs_attr_pwrite(log_na, 0, blocksz, buffer) == blocksz) @@ -3002,8 +3002,8 @@ static const struct BUFFER *best_start(const struct BUFFER *buf, const struct BUFFER *altbuf) { const struct BUFFER *best; - const struct RECORD_PAGE_HEADER *head; - const struct RECORD_PAGE_HEADER *althead; + const RECORD_PAGE_HEADER *head; + const RECORD_PAGE_HEADER *althead; s64 diff; if (!buf || !altbuf) @@ -3109,8 +3109,8 @@ static int locatelogfile(CONTEXT *ctx) static BOOL getlogfiledata(CONTEXT *ctx, const char *boot) { - const struct RESTART_PAGE_HEADER *rph; - const struct RESTART_AREA *rest; + const RESTART_PAGE_HEADER *rph; + const RESTART_AREA *rest; BOOL ok; u32 off; s64 size; @@ -3118,9 +3118,9 @@ static BOOL getlogfiledata(CONTEXT *ctx, const char *boot) ok = FALSE; fseek(ctx->file,0L,2); size = ftell(ctx->file); - rph = (const struct RESTART_PAGE_HEADER*)boot; + rph = (const RESTART_PAGE_HEADER*)boot; off = le16_to_cpu(rph->restart_offset); - rest = (const struct RESTART_AREA*)&boot[off]; + rest = (const RESTART_AREA*)&boot[off]; /* estimate cluster size from log file size (unreliable) */ switch (le32_to_cpu(rest->seq_number_bits)) { @@ -3155,11 +3155,11 @@ static BOOL getlogfiledata(CONTEXT *ctx, const char *boot) static BOOL getvolumedata(CONTEXT *ctx, char *boot) { - const struct RESTART_AREA *rest; + const RESTART_AREA *rest; BOOL ok; ok = FALSE; - rest = (const struct RESTART_AREA*)NULL; + rest = (const RESTART_AREA*)NULL; if (ctx->vol) { getboot(boot); mftlcn = ctx->vol->mft_lcn; @@ -3267,7 +3267,7 @@ static u16 dorcrd(CONTEXT *ctx, u32 blk, u16 pos, const struct BUFFER *buf, static TRISTATE backoverlap(CONTEXT *ctx, int blk, const char *data, const char *nextdata, int k) { - const struct LOG_RECORD *logr; + const LOG_RECORD *logr; char *fullrec; s32 size; int space; @@ -3275,11 +3275,11 @@ static TRISTATE backoverlap(CONTEXT *ctx, int blk, TRISTATE state; u16 blkheadsz; - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; state = T_ERR; size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ; space = blocksz - k; - blkheadsz = sizeof(struct RECORD_PAGE_HEADER) + blkheadsz = sizeof(RECORD_PAGE_HEADER) + ((2*getle16(data,6) - 1) | 7) + 1; nextspace = blocksz - blkheadsz; if ((space >= LOG_RECORD_HEAD_SZ) @@ -3318,7 +3318,7 @@ static TRISTATE backoverlap(CONTEXT *ctx, int blk, } } - state = (likelyop((struct LOG_RECORD*)fullrec) ? T_OK : T_ERR); + state = (likelyop((LOG_RECORD*)fullrec) ? T_OK : T_ERR); actionnum++; if (optv) { printf("\nOverlapping backward action %d at 0x%x" @@ -3330,10 +3330,10 @@ static TRISTATE backoverlap(CONTEXT *ctx, int blk, (long)blk,(int)space,(state == T_OK)); } if (state == T_OK) { - showlogr(ctx, k, (struct LOG_RECORD*)fullrec); + showlogr(ctx, k, (LOG_RECORD*)fullrec); if (optp || optu || opts) state = enqueue_action(ctx, - (struct LOG_RECORD*)fullrec, + (LOG_RECORD*)fullrec, size, actionnum); } else { /* Try to go on unless playing actions */ @@ -3362,10 +3362,10 @@ static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped, const struct BUFFER *buf, const struct BUFFER *prevbuf, const struct BUFFER *nextbuf) { - u16 poslist[75]; /* 4096/sizeof(struct LOG_RECORD) */ - const struct RECORD_PAGE_HEADER *rph; - const struct RECORD_PAGE_HEADER *prevrph; - const struct LOG_RECORD *logr; + u16 poslist[75]; /* 4096/sizeof(LOG_RECORD) */ + const RECORD_PAGE_HEADER *rph; + const RECORD_PAGE_HEADER *prevrph; + const LOG_RECORD *logr; const char *data; const char *nextdata; BOOL stop; @@ -3378,7 +3378,7 @@ static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped, state = T_ERR; rph = &buf->block.record; - prevrph = (struct RECORD_PAGE_HEADER*)NULL; + prevrph = (RECORD_PAGE_HEADER*)NULL; if (prevbuf) prevrph = &prevbuf->block.record; data = buf->block.data; @@ -3399,12 +3399,12 @@ static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped, k = buf->headsz; else k = firstrecord(skipped, buf, prevbuf); - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; cnt = 0; /* check whether there is at least one beginning of record */ endoff = le16_to_cpu(rph->next_record_offset); if (k && ((k < endoff) || !endoff)) { - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; if (likelyop(logr)) { stop = FALSE; state = T_OK; @@ -3430,7 +3430,7 @@ static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped, } } while (!stop) { - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ; if ((size < MINRECSIZE) @@ -3472,7 +3472,7 @@ static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped, } for (j=cnt-1; (j>=0) && (state==T_OK); j--) { k = poslist[j]; - logr = (const struct LOG_RECORD*)&data[k]; + logr = (const LOG_RECORD*)&data[k]; size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ; actionnum++; @@ -3599,7 +3599,7 @@ static int walk(CONTEXT *ctx) const struct BUFFER *prevbuf; const struct BUFFER *startbuf; const NTFS_RECORD *record; - const struct RECORD_PAGE_HEADER *rph; + const RECORD_PAGE_HEADER *rph; NTFS_RECORD_TYPES magic; u32 blk; u32 nextblk; @@ -4052,28 +4052,28 @@ static BOOL checkstructs(void) BOOL ok; ok = TRUE; - if (sizeof(struct RECORD_PAGE_HEADER) != 40) { + if (sizeof(RECORD_PAGE_HEADER) != 40) { fprintf(stderr, - "* error : bad sizeof(struct RECORD_PAGE_HEADER) %d\n", - (int)sizeof(struct RECORD_PAGE_HEADER)); + "* error : bad sizeof(RECORD_PAGE_HEADER) %d\n", + (int)sizeof(RECORD_PAGE_HEADER)); ok = FALSE; } - if (sizeof(struct LOG_RECORD) != 88) { + if (sizeof(LOG_RECORD) != 88) { fprintf(stderr, - "* error : bad sizeof(struct LOG_RECORD) %d\n", - (int)sizeof(struct LOG_RECORD)); + "* error : bad sizeof(LOG_RECORD) %d\n", + (int)sizeof(LOG_RECORD)); ok = FALSE; } - if (sizeof(struct RESTART_PAGE_HEADER) != 32) { + if (sizeof(RESTART_PAGE_HEADER) != 32) { fprintf(stderr, - "* error : bad sizeof(struct RESTART_PAGE_HEADER) %d\n", - (int)sizeof(struct RESTART_PAGE_HEADER)); + "* error : bad sizeof(RESTART_PAGE_HEADER) %d\n", + (int)sizeof(RESTART_PAGE_HEADER)); ok = FALSE; } - if (sizeof(struct RESTART_AREA) != 44) { + if (sizeof(RESTART_AREA) != 44) { fprintf(stderr, - "* error : bad sizeof(struct RESTART_AREA) %d\n", - (int)sizeof(struct RESTART_AREA)); + "* error : bad sizeof(RESTART_AREA) %d\n", + (int)sizeof(RESTART_AREA)); ok = FALSE; } if (sizeof(struct ATTR_OLD) != 44) { diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index 692aa178..6bbfb9cd 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -128,7 +128,7 @@ typedef enum { /* ntfsdoc p 39 (47), not in layout.h */ -typedef struct RESTART_PAGE_HEADER { /* size 32 */ +typedef struct { /* size 32 */ NTFS_RECORD head; leLSN chkdsk_lsn; le32 system_page_size; @@ -141,7 +141,7 @@ typedef struct RESTART_PAGE_HEADER { /* size 32 */ /* ntfsdoc p 40 (48), not in layout.h */ -struct RESTART_AREA { /* size 44 */ +typedef struct { /* size 44 */ leLSN current_lsn; le16 log_clients; le16 client_free_list; @@ -155,9 +155,9 @@ struct RESTART_AREA { /* size 44 */ le16 record_length; le16 log_page_data_offset; le32 restart_log_open_count; -} __attribute__((__packed__)) ; +} __attribute__((__packed__)) RESTART_AREA; -typedef struct RESTART_CLIENT { /* size 160 */ +typedef struct { /* size 160 */ /*Ofs*/ /* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create set to 0. */ @@ -194,7 +194,7 @@ typedef struct RESTART_CLIENT { /* size 160 */ /* ntfsdoc p 41 (49), not in layout.h */ -struct RECORD_PAGE_HEADER { /* size 40 */ +typedef struct { /* size 40 */ NTFS_RECORD head; /* the magic is "RCRD" */ union { leLSN last_lsn; @@ -206,13 +206,13 @@ struct RECORD_PAGE_HEADER { /* size 40 */ le16 next_record_offset; le16 reserved4[3]; leLSN last_end_lsn; -} __attribute__((__packed__)) ; +} __attribute__((__packed__)) RECORD_PAGE_HEADER; /* ntfsdoc p 42 (50), not in layout.h */ #define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */ -typedef struct LOG_RECORD { /* size 80 */ +typedef struct { /* size 80 */ leLSN this_lsn; leLSN client_previous_lsn; leLSN client_undo_next_lsn; @@ -259,8 +259,8 @@ struct BUFFER { unsigned int headsz; BOOL safe; union { - struct RESTART_PAGE_HEADER restart; - struct RECORD_PAGE_HEADER record; + RESTART_PAGE_HEADER restart; + RECORD_PAGE_HEADER record; char data[1]; } block; /* variable length, keep at the end */ } ; @@ -270,7 +270,7 @@ struct ACTION_RECORD { struct ACTION_RECORD *prev; int num; unsigned int flags; - struct LOG_RECORD record; /* variable length, keep at the end */ + LOG_RECORD record; /* variable length, keep at the end */ } ; enum { /* Flag values for ACTION_RECORD */ @@ -336,19 +336,19 @@ extern u64 synced_lsn; extern u64 latest_lsn; extern u64 restart_lsn; -extern struct RESTART_AREA restart; -extern struct RESTART_CLIENT client; +extern RESTART_AREA restart; +extern LOG_CLIENT_RECORD client; const char *actionname(int op); const char *mftattrname(ATTR_TYPES attr); void showname(const char *prefix, const char *name, int cnt); int fixnamelen(const char *name, int len); -BOOL within_lcn_range(const struct LOG_RECORD *logr); +BOOL within_lcn_range(const LOG_RECORD *logr); struct ATTR *getattrentry(unsigned int key, unsigned int lth); void copy_attribute(struct ATTR *pa, const char *buf, int length); -u32 get_undo_offset(const struct LOG_RECORD *logr); -u32 get_redo_offset(const struct LOG_RECORD *logr); -u32 get_extra_offset(const struct LOG_RECORD *logr); +u32 get_undo_offset(const LOG_RECORD *logr); +u32 get_redo_offset(const LOG_RECORD *logr); +u32 get_extra_offset(const LOG_RECORD *logr); BOOL exception(int num); struct STORE; diff --git a/ntfsprogs/playlog.c b/ntfsprogs/playlog.c index 83d63071..63f4189a 100644 --- a/ntfsprogs/playlog.c +++ b/ntfsprogs/playlog.c @@ -117,7 +117,7 @@ static void locate(const char *s, int n, const char *p, int m) } */ -static u64 inode_number(const struct LOG_RECORD *logr) +static u64 inode_number(const LOG_RECORD *logr) { u64 offset; @@ -409,7 +409,7 @@ static int sanity_indx(ntfs_volume *vol, const char *buffer) * With option -n reading is first attempted from the memory store */ -static char *read_raw(ntfs_volume *vol, const struct LOG_RECORD *logr) +static char *read_raw(ntfs_volume *vol, const LOG_RECORD *logr) { char *buffer; char *target; @@ -477,7 +477,7 @@ static char *read_raw(ntfs_volume *vol, const struct LOG_RECORD *logr) * With option -n a copy of the buffer is kept in memory for later use. */ -static int write_raw(ntfs_volume *vol, const struct LOG_RECORD *logr, +static int write_raw(ntfs_volume *vol, const LOG_RECORD *logr, char *buffer) { int err; @@ -532,7 +532,7 @@ static int write_raw(ntfs_volume *vol, const struct LOG_RECORD *logr, * Write a full set of raw clusters to mft_mirr */ -static int write_mirr(ntfs_volume *vol, const struct LOG_RECORD *logr, +static int write_mirr(ntfs_volume *vol, const LOG_RECORD *logr, char *buffer) { int err; @@ -566,7 +566,7 @@ static int write_mirr(ntfs_volume *vol, const struct LOG_RECORD *logr, * Allocate a buffer and read a single protected record */ -static char *read_protected(ntfs_volume *vol, const struct LOG_RECORD *logr, +static char *read_protected(ntfs_volume *vol, const LOG_RECORD *logr, u32 size, BOOL warn) { char *buffer; @@ -614,7 +614,7 @@ static char *read_protected(ntfs_volume *vol, const struct LOG_RECORD *logr, * than a cluster, have to read, merge and write. */ -static int write_protected(ntfs_volume *vol, const struct LOG_RECORD *logr, +static int write_protected(ntfs_volume *vol, const LOG_RECORD *logr, char *buffer, u32 size) { MFT_RECORD *record; From a6f4bae6d56a9d5af3ef5af62d28c4a8f8fb6b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:34:46 +0200 Subject: [PATCH 16/86] Typedef'ed new structs in ntfsrecover the same way as in logfile.h Prepare merging ntfsrecover.h into logfile.h by declaring new structs the same was as in logfile.h --- ntfsprogs/ntfsrecover.c | 22 +++++++++++----------- ntfsprogs/ntfsrecover.h | 14 +++++++++++--- ntfsprogs/playlog.c | 24 ++++++++++++------------ 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index 798a0d0f..09bedba8 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -1153,13 +1153,13 @@ void copy_attribute(struct ATTR *pa, const char *buf, int length) if (pa) { switch (length) { - case sizeof(struct ATTR_NEW) : - panew = (const struct ATTR_NEW*)buf; + case sizeof(ATTR_NEW) : + panew = (const ATTR_NEW*)buf; pa->type = panew->type; pa->lsn = sle64_to_cpu(panew->lsn); pa->inode = MREF(le64_to_cpu(panew->inode)); break; - case sizeof(struct ATTR_OLD) : + case sizeof(ATTR_OLD) : /* Badly aligned, first realign */ memcpy(&old_aligned,buf,sizeof(old_aligned)); pa->type = old_aligned.type; @@ -1758,8 +1758,8 @@ static void fixup(CONTEXT *ctx, const LOG_RECORD *logr, const char *buf, * Changed from Win10, formerly we got step = 44. * The record layout has also changed */ - if ((step != sizeof(struct ATTR_OLD)) - && (step != sizeof(struct ATTR_NEW))) { + if ((step != sizeof(ATTR_OLD)) + && (step != sizeof(ATTR_NEW))) { printf(" ** Unexpected step %d\n",step); } more = 0; @@ -4076,16 +4076,16 @@ static BOOL checkstructs(void) (int)sizeof(RESTART_AREA)); ok = FALSE; } - if (sizeof(struct ATTR_OLD) != 44) { + if (sizeof(ATTR_OLD) != 44) { fprintf(stderr, - "* error : bad sizeof(struct ATTR_OLD) %d\n", - (int)sizeof(struct ATTR_OLD)); + "* error : bad sizeof(ATTR_OLD) %d\n", + (int)sizeof(ATTR_OLD)); ok = FALSE; } - if (sizeof(struct ATTR_NEW) != 40) { + if (sizeof(ATTR_NEW) != 40) { fprintf(stderr, - "* error : bad sizeof(struct ATTR_NEW) %d\n", - (int)sizeof(struct ATTR_NEW)); + "* error : bad sizeof(ATTR_NEW) %d\n", + (int)sizeof(ATTR_NEW)); ok = FALSE; } if (LastAction != 38) { diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index 6bbfb9cd..3896825d 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -291,8 +291,16 @@ struct BITMAP_ACTION { le32 count; } ; -/* Danger in arrays : contains le64's though size is not a multiple of 8 */ -typedef struct ATTR_OLD { /* Format up to Win10 (44 bytes) */ +/** + * struct ATTR - Attribute record. + * + * The format of an attribute record has changed from Windows 10. + * The old format was 44 bytes long, despite having 8 bytes fields, + * and this leads to alignment problems in arrays. + * This problem does not occur in the new format, which is shorter. + * The format being used can generally be determined from size. + */ +typedef struct { /* Format up to Win10 (44 bytes) */ le64 unknown1; le64 unknown2; le64 inode; @@ -302,7 +310,7 @@ typedef struct ATTR_OLD { /* Format up to Win10 (44 bytes) */ le32 unknown4; } __attribute__((__packed__)) ATTR_OLD; -typedef struct ATTR_NEW { /* Format since Win10 (40 bytes) */ +typedef struct { /* Format since Win10 (40 bytes) */ le64 unknown1; le64 unknown2; le32 type; diff --git a/ntfsprogs/playlog.c b/ntfsprogs/playlog.c index 63f4189a..72e1ecee 100644 --- a/ntfsprogs/playlog.c +++ b/ntfsprogs/playlog.c @@ -2309,8 +2309,8 @@ static int redo_open_attribute(ntfs_volume *vol __attribute__((unused)), { const char *data; struct ATTR *pa; - const struct ATTR_OLD *attr_old; - const struct ATTR_NEW *attr_new; + const ATTR_OLD *attr_old; + const ATTR_NEW *attr_new; const char *name; le64 inode; u32 namelen; @@ -2349,15 +2349,15 @@ static int redo_open_attribute(ntfs_volume *vol __attribute__((unused)), * whether it matches what we have in store. */ switch (length) { - case sizeof(struct ATTR_OLD) : - attr_old = (const struct ATTR_OLD*)data; + case sizeof(ATTR_OLD) : + attr_old = (const ATTR_OLD*)data; /* Badly aligned */ memcpy(&inode, &attr_old->inode, 8); err = (MREF(le64_to_cpu(inode)) != pa->inode) || (attr_old->type != pa->type); break; - case sizeof(struct ATTR_NEW) : - attr_new = (const struct ATTR_NEW*)data; + case sizeof(ATTR_NEW) : + attr_new = (const ATTR_NEW*)data; err = (MREF(le64_to_cpu(attr_new->inode)) != pa->inode) || (attr_new->type != pa->type); @@ -3379,8 +3379,8 @@ static int undo_open_attribute(ntfs_volume *vol __attribute__((unused)), { const char *data; struct ATTR *pa; - const struct ATTR_OLD *attr_old; - const struct ATTR_NEW *attr_new; + const ATTR_OLD *attr_old; + const ATTR_NEW *attr_new; const char *name; le64 inode; u32 namelen; @@ -3415,15 +3415,15 @@ static int undo_open_attribute(ntfs_volume *vol __attribute__((unused)), if (pa) { /* check whether the redo attr matches what we have in store */ switch (length) { - case sizeof(struct ATTR_OLD) : - attr_old = (const struct ATTR_OLD*)data; + case sizeof(ATTR_OLD) : + attr_old = (const ATTR_OLD*)data; /* Badly aligned */ memcpy(&inode, &attr_old->inode, 8); err = (MREF(le64_to_cpu(inode)) != pa->inode) || (attr_old->type != pa->type); break; - case sizeof(struct ATTR_NEW) : - attr_new = (const struct ATTR_NEW*)data; + case sizeof(ATTR_NEW) : + attr_new = (const ATTR_NEW*)data; err = (MREF(le64_to_cpu(attr_new->inode))!= pa->inode) || (attr_new->type != pa->type); break; From d947ffa8345f893fdabc801cf96e3d038bc8ef22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:38:06 +0200 Subject: [PATCH 17/86] Unfolded record headers in ntfsrecover the same way as in logfile.h Prepare merging ntfsrecover.h into logfile.h by unfolding the record headers the same way. --- ntfsprogs/ntfsrecover.c | 42 ++++++++++++++++++++--------------------- ntfsprogs/ntfsrecover.h | 8 ++++++-- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index 09bedba8..d4d6e185 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -218,8 +218,8 @@ static int replaceusa(struct BUFFER *buffer, unsigned int lth) /* Do not check beyond used sectors */ record = &buffer->block.record; used = blocksz; - xusa = le16_to_cpu(record->head.usa_ofs); - nusa = le16_to_cpu(record->head.usa_count); + xusa = le16_to_cpu(record->usa_ofs); + nusa = le16_to_cpu(record->usa_count); if (xusa && nusa && ((xusa + 1) < lth) && ((nusa - 1)*NTFSBLKLTH == lth)) { @@ -2365,11 +2365,11 @@ static void showheadrcrd(u32 blk, const RECORD_PAGE_HEADER *rph) if (optv) { printf("magic %08lx\n", - (long)le32_to_cpu(rph->head.magic)); + (long)le32_to_cpu(rph->magic)); printf("usa_ofs %04x\n", - (int)le16_to_cpu(rph->head.usa_ofs)); + (int)le16_to_cpu(rph->usa_ofs)); printf("usa_count %04x\n", - (int)le16_to_cpu(rph->head.usa_count)); + (int)le16_to_cpu(rph->usa_count)); if (blk < 4) printf("file_offset %08lx\n", (long)le32_to_cpu(rph->copy.file_offset)); @@ -2397,7 +2397,7 @@ static void showheadrcrd(u32 blk, const RECORD_PAGE_HEADER *rph) (long long)sle64_to_cpu(rph->last_end_lsn), (diff < 0 ? "" : "+"),(long)diff); printf("usn %04x\n", - (int)getle16(rph,le16_to_cpu(rph->head.usa_ofs))); + (int)getle16(rph,le16_to_cpu(rph->usa_ofs))); printf("\n"); } else { if (optt) { @@ -2597,7 +2597,7 @@ static u16 forward_rcrd(CONTEXT *ctx, u32 blk, u16 pos, BOOL stop; rph = &buf->block.record; - if (rph && (rph->head.magic == magic_RCRD)) { + if (rph && (rph->magic == magic_RCRD)) { data = buf->block.data; showheadrcrd(blk, rph); k = buf->headsz; @@ -2674,7 +2674,7 @@ static u16 forward_rcrd(CONTEXT *ctx, u32 blk, u16 pos, } } else { printf("** Not a RCRD record, MAGIC 0x%08lx\n", - (long)le32_to_cpu(rph->head.magic)); + (long)le32_to_cpu(rph->magic)); k = 0; } return (k); @@ -2691,15 +2691,15 @@ static void showrest(const RESTART_PAGE_HEADER *rest) const char *data; data = (const char*)rest; - if ((rest->head.magic == magic_RSTR) - || (rest->head.magic == magic_CHKD)) { + if ((rest->magic == magic_RSTR) + || (rest->magic == magic_CHKD)) { if (optv) { printf("magic %08lx\n", - (long)le32_to_cpu(rest->head.magic)); + (long)le32_to_cpu(rest->magic)); printf("usa_ofs %04x\n", - (int)le16_to_cpu(rest->head.usa_ofs)); + (int)le16_to_cpu(rest->usa_ofs)); printf("usa_count %04x\n", - (int)le16_to_cpu(rest->head.usa_count)); + (int)le16_to_cpu(rest->usa_count)); printf("chkdsk_lsn %016llx\n", (long long)sle64_to_cpu(rest->chkdsk_lsn)); printf("system_page_size %08lx\n", @@ -2787,7 +2787,7 @@ static void showrest(const RESTART_PAGE_HEADER *rest) } } else printf("Not a RSTR or CHKD record, MAGIC 0x%08lx\n", - (long)le32_to_cpu(rest->head.magic)); + (long)le32_to_cpu(rest->magic)); } static BOOL dorest(CONTEXT *ctx, unsigned long blk, @@ -2925,7 +2925,7 @@ static const struct BUFFER *read_restart(CONTEXT *ctx) if (buf) { NTFS_RECORD_TYPES magic; - magic = buf->block.restart.head.magic; + magic = buf->block.restart.magic; switch (magic) { case magic_RSTR : break; @@ -3019,7 +3019,7 @@ static const struct BUFFER *best_start(const struct BUFFER *buf, else best = buf; } - if (best && (best->block.record.head.magic != magic_RCRD)) + if (best && (best->block.record.magic != magic_RCRD)) best = (const struct BUFFER*)NULL; return (best); } @@ -3382,8 +3382,8 @@ static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped, if (prevbuf) prevrph = &prevbuf->block.record; data = buf->block.data; - if (rph && (rph->head.magic == magic_RCRD) - && (!prevrph || (prevrph->head.magic == magic_RCRD))) { + if (rph && (rph->magic == magic_RCRD) + && (!prevrph || (prevrph->magic == magic_RCRD))) { if (optv) { if (optv >= 2) hexdump(data,blocksz); @@ -3537,7 +3537,7 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk, else skipped = blk - prevblk - 1 + (logfilesz >> blockbits) - BASEBLKS; - magic = prevbuf->block.record.head.magic; + magic = prevbuf->block.record.magic; switch (magic) { case magic_RCRD : break; @@ -3652,7 +3652,7 @@ static int walk(CONTEXT *ctx) err = 1; break; } - magic = buf->block.record.head.magic; + magic = buf->block.record.magic; switch (magic) { case magic_CHKD : case magic_RSTR : @@ -3790,7 +3790,7 @@ static int walk(CONTEXT *ctx) prevbuf = findprevious(ctx, buf); if (prevbuf) { prevblk = prevbuf->num; - magic = prevbuf->block.record.head.magic; + magic = prevbuf->block.record.magic; switch (magic) { case magic_RCRD : break; diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index 3896825d..732e57ac 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -129,7 +129,9 @@ typedef enum { /* ntfsdoc p 39 (47), not in layout.h */ typedef struct { /* size 32 */ - NTFS_RECORD head; + NTFS_RECORD_TYPES magic; + le16 usa_ofs; + le16 usa_count; leLSN chkdsk_lsn; le32 system_page_size; le32 log_page_size; @@ -195,7 +197,9 @@ typedef struct { /* size 160 */ /* ntfsdoc p 41 (49), not in layout.h */ typedef struct { /* size 40 */ - NTFS_RECORD head; /* the magic is "RCRD" */ + NTFS_RECORD_TYPES magic; + le16 usa_ofs; + le16 usa_count; union { leLSN last_lsn; le32 file_offset; From 044f2104f9cc6d64f0e8fec478cb71f916030bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:40:28 +0200 Subject: [PATCH 18/86] Redefined file_offset on 64 bits in ntfsrecover.h The log file offsets are apparently stored on 64 bits, though the file size is unlikely to reach 2MB. --- ntfsprogs/ntfsrecover.c | 6 +++--- ntfsprogs/ntfsrecover.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index d4d6e185..d1262aa9 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -1101,7 +1101,7 @@ static const struct BUFFER *findprevious(CONTEXT *ctx, const struct BUFFER *buf) prevblk = (logfilesz >> blockbits) - 1; else { rph = &buf->block.record; - prevblk = (le32_to_cpu(rph->copy.file_offset) + prevblk = (sle64_to_cpu(rph->copy.file_offset) >> blockbits) - 1; /* * If an initial block leads to block 4, it @@ -2371,8 +2371,8 @@ static void showheadrcrd(u32 blk, const RECORD_PAGE_HEADER *rph) printf("usa_count %04x\n", (int)le16_to_cpu(rph->usa_count)); if (blk < 4) - printf("file_offset %08lx\n", - (long)le32_to_cpu(rph->copy.file_offset)); + printf("file_offset %016llx\n", + (long long)sle64_to_cpu(rph->copy.file_offset)); else { diff = sle64_to_cpu(rph->copy.last_lsn) - synced_lsn; printf("last_lsn %016llx" diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index 732e57ac..7ac84f43 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -202,7 +202,7 @@ typedef struct { /* size 40 */ le16 usa_count; union { leLSN last_lsn; - le32 file_offset; + sle64 file_offset; } __attribute__((__packed__)) copy; le32 flags; le16 page_count; From ad59ecec3ff76d6891a838e98497da4331c61f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:45:30 +0200 Subject: [PATCH 19/86] Redefined target_vcn on 64 bits in ntfsrecover.h In a log record, the target vcn has to be stored on 64 bits --- ntfsprogs/ntfsrecover.c | 18 ++++++++---------- ntfsprogs/ntfsrecover.h | 3 +-- ntfsprogs/playlog.c | 12 ++++++------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index d1262aa9..c5948962 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -1320,7 +1320,7 @@ static void fixup(CONTEXT *ctx, const LOG_RECORD *logr, const char *buf, } printf(" new base MFT record, attr 0x%x (%s)\n",attr,attrname(attr)); printf(" inode %lld\n", - (((long long)le32_to_cpu(logr->target_vcn) + (((long long)le64_to_cpu(logr->target_vcn) << clusterbits) + (le16_to_cpu(logr->cluster_index) << 9)) >> mftrecbits); @@ -1369,7 +1369,7 @@ static void fixup(CONTEXT *ctx, const LOG_RECORD *logr, const char *buf, printf(" free base MFT record, attr 0x%x (%s)\n", attr,attrname(attr)); printf(" inode %lld\n", - (((long long)le32_to_cpu(logr->target_vcn) << clusterbits) + (((long long)le64_to_cpu(logr->target_vcn) << clusterbits) + (le16_to_cpu(logr->cluster_index) << 9)) >> mftrecbits); break; case CreateAttribute : /* 5 */ @@ -1877,20 +1877,18 @@ static void detaillogr(CONTEXT *ctx, const LOG_RECORD *logr) printf("attribute_flags %04x\n", (int)le16_to_cpu(logr->attribute_flags)); if (mftrecbits && onmft) - printf("target_vcn %08lx (inode %lld)\n", - (long)le32_to_cpu(logr->target_vcn), - (((long long)le32_to_cpu(logr->target_vcn) + printf("target_vcn %016llx (inode %lld)\n", + (long long)le64_to_cpu(logr->target_vcn), + (((long long)le64_to_cpu(logr->target_vcn) << clusterbits) + (le16_to_cpu(logr->cluster_index) << 9)) >> mftrecbits); else - printf("target_vcn %08lx\n", - (long)le32_to_cpu(logr->target_vcn)); - printf("reserved3 %08lx\n", - (long)le32_to_cpu(logr->reserved3)); + printf("target_vcn %016llx\n", + (long long)le64_to_cpu(logr->target_vcn)); /* Compute a base for the current run of mft */ baselcn = le64_to_cpu(logr->lcn_list[0]) - - le32_to_cpu(logr->target_vcn); + - le64_to_cpu(logr->target_vcn); for (i=0; ilcns_to_follow) && (ilcn_list[i]); diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index 7ac84f43..4ca269d8 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -243,8 +243,7 @@ typedef struct { /* size 80 */ le16 attribute_offset; le16 cluster_index; ATTRIBUTE_FLAGS attribute_flags; - le32 target_vcn; - le32 reserved3; + leVCN target_vcn; le64 lcn_list[0]; } __attribute__((__packed__)); struct { diff --git a/ntfsprogs/playlog.c b/ntfsprogs/playlog.c index 72e1ecee..40781462 100644 --- a/ntfsprogs/playlog.c +++ b/ntfsprogs/playlog.c @@ -121,7 +121,7 @@ static u64 inode_number(const LOG_RECORD *logr) { u64 offset; - offset = ((u64)le32_to_cpu(logr->target_vcn) + offset = ((u64)le64_to_cpu(logr->target_vcn) << clusterbits) + ((u32)le16_to_cpu(logr->cluster_index) << NTFS_BLOCK_SIZE_BITS); @@ -548,7 +548,7 @@ static int write_mirr(ntfs_volume *vol, const LOG_RECORD *logr, if (!optn) { for (i=0; (imftmirr_na, - le32_to_cpu(logr->target_vcn) + i); + le64_to_cpu(logr->target_vcn) + i); source = buffer + clustersz*i; if ((lcn < 0) || (ntfs_pwrite(vol->dev, lcn << clusterbits, @@ -640,15 +640,15 @@ static int write_protected(ntfs_volume *vol, const LOG_RECORD *logr, "older" : "newer"), (long long)sle64_to_cpu(logr->this_lsn)); if (optv > 1) - printf("mft vcn %ld index %d\n", - (long)le32_to_cpu(logr->target_vcn), + printf("mft vcn %lld index %d\n", + (long long)le64_to_cpu(logr->target_vcn), (int)le16_to_cpu(logr->cluster_index)); err = sanity_mft(buffer); /* Should set to some previous lsn for undos */ if (opts) record->lsn = logr->this_lsn; /* Duplicate on mftmirr if not overflowing its size */ - mftmirr = (((u64)le32_to_cpu(logr->target_vcn) + mftmirr = (((u64)le64_to_cpu(logr->target_vcn) + le16_to_cpu(logr->lcns_to_follow)) << clusterbits) <= (((u64)vol->mftmirr_size) << mftrecbits); @@ -1786,7 +1786,7 @@ static int create_indx(ntfs_volume *vol, const struct ACTION_RECORD *action, indx->usa_ofs = const_cpu_to_le16(0x28); indx->usa_count = const_cpu_to_le16(9); indx->lsn = action->record.this_lsn; - vcn = le32_to_cpu(action->record.target_vcn); + vcn = le64_to_cpu(action->record.target_vcn); /* beware of size change on big-endian cpus */ indx->index_block_vcn = cpu_to_sle64(vcn); /* INDEX_HEADER */ From b977f18c6ef69c3e324d9eb867c9237d4f9aeaf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:50:31 +0200 Subject: [PATCH 20/86] Renamed restart_offset as restart_area_offset in ntfsrecover.h Prepare merging ntfsrecover.h into logfile.h by renaming the restart offset the same way. --- ntfsprogs/ntfsrecover.c | 18 +++++++++--------- ntfsprogs/ntfsrecover.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index c5948962..b04fb8f3 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -2704,8 +2704,8 @@ static void showrest(const RESTART_PAGE_HEADER *rest) (long)le32_to_cpu(rest->system_page_size)); printf("log_page_size %08lx\n", (long)le32_to_cpu(rest->log_page_size)); - printf("restart_offset %04x\n", - (int)le16_to_cpu(rest->restart_offset)); + printf("restart_area_offset %04x\n", + (int)le16_to_cpu(rest->restart_area_offset)); printf("minor_vers %d\n", (int)le16_to_cpu(rest->minor_ver)); printf("major_vers %d\n", @@ -2719,7 +2719,7 @@ static void showrest(const RESTART_PAGE_HEADER *rest) (long long)sle64_to_cpu(rest->chkdsk_lsn)); } resa = (const RESTART_AREA*) - &data[le16_to_cpu(rest->restart_offset)]; + &data[le16_to_cpu(rest->restart_area_offset)]; if (optv) { printf("current_lsn %016llx\n", (long long)sle64_to_cpu(resa->current_lsn)); @@ -2755,7 +2755,7 @@ static void showrest(const RESTART_PAGE_HEADER *rest) } rcli = (const LOG_CLIENT_RECORD*) - &data[le16_to_cpu(rest->restart_offset) + &data[le16_to_cpu(rest->restart_area_offset) + le16_to_cpu(resa->client_array_offset)]; if (optv) { printf("oldest_lsn %016llx\n", @@ -2801,7 +2801,7 @@ static BOOL dorest(CONTEXT *ctx, unsigned long blk, BOOL dirty; data = (const char*)rph; - offs = le16_to_cpu(rph->restart_offset); + offs = le16_to_cpu(rph->restart_area_offset); resa = (const RESTART_AREA*)&data[offs]; rcli = (const LOG_CLIENT_RECORD*)&data[offs + le16_to_cpu(resa->client_array_offset)]; @@ -2812,7 +2812,7 @@ static BOOL dorest(CONTEXT *ctx, unsigned long blk, synced_lsn = sle64_to_cpu(rcli->oldest_lsn); memcpy(&log_header, rph, sizeof(RESTART_PAGE_HEADER)); - offs = le16_to_cpu(log_header.restart_offset); + offs = le16_to_cpu(log_header.restart_area_offset); memcpy(&restart, &data[offs], sizeof(RESTART_AREA)); offs += le16_to_cpu(restart.client_array_offset); @@ -2858,7 +2858,7 @@ static BOOL dorest(CONTEXT *ctx, unsigned long blk, latest_lsn = sle64_to_cpu(resa->current_lsn); memcpy(&log_header, rph, sizeof(RESTART_PAGE_HEADER)); - offs = le16_to_cpu(log_header.restart_offset); + offs = le16_to_cpu(log_header.restart_area_offset); memcpy(&restart, &data[offs], sizeof(RESTART_AREA)); offs += le16_to_cpu(restart.client_array_offset); @@ -2975,7 +2975,7 @@ static int reset_logfile(CONTEXT *ctx __attribute__((unused))) client.oldest_lsn = cpu_to_sle64(restart_lsn); memcpy(buffer, &log_header, sizeof(RESTART_PAGE_HEADER)); - off = le16_to_cpu(log_header.restart_offset); + off = le16_to_cpu(log_header.restart_area_offset); memcpy(&buffer[off], &restart, sizeof(RESTART_AREA)); off += le16_to_cpu(restart.client_array_offset); @@ -3117,7 +3117,7 @@ static BOOL getlogfiledata(CONTEXT *ctx, const char *boot) fseek(ctx->file,0L,2); size = ftell(ctx->file); rph = (const RESTART_PAGE_HEADER*)boot; - off = le16_to_cpu(rph->restart_offset); + off = le16_to_cpu(rph->restart_area_offset); rest = (const RESTART_AREA*)&boot[off]; /* estimate cluster size from log file size (unreliable) */ diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index 4ca269d8..44fa60e9 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -135,7 +135,7 @@ typedef struct { /* size 32 */ leLSN chkdsk_lsn; le32 system_page_size; le32 log_page_size; - le16 restart_offset; + le16 restart_area_offset; le16 minor_ver; le16 major_ver; le16 usn; From 234cae2a1beae6e3e148f201ea5fb90431b06a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:52:18 +0200 Subject: [PATCH 21/86] Renamed record_length as log_record_header_length in ntfsrecover.h Prepare merging ntfsrecover.h into logfile.h by naming the record header length the same way. --- ntfsprogs/ntfsrecover.c | 2 +- ntfsprogs/ntfsrecover.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index b04fb8f3..3f78bede 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -2742,7 +2742,7 @@ static void showrest(const RESTART_PAGE_HEADER *rest) printf("last_lsn_data_len %08lx\n", (long)le32_to_cpu(resa->last_lsn_data_length)); printf("record_length %04x\n", - (int)le16_to_cpu(resa->record_length)); + (int)le16_to_cpu(resa->log_record_header_length)); printf("log_page_data_offs %04x\n", (int)le16_to_cpu(resa->log_page_data_offset)); printf("restart_log_open_count %08lx\n", diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index 44fa60e9..fec74ed3 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -154,7 +154,7 @@ typedef struct { /* size 44 */ le16 client_array_offset; le64 file_size; le32 last_lsn_data_length; - le16 record_length; + le16 log_record_header_length; le16 log_page_data_offset; le32 restart_log_open_count; } __attribute__((__packed__)) RESTART_AREA; From 60ba821ece51dfd9fe4b53b0e4ccc2a430cebf75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:54:51 +0200 Subject: [PATCH 22/86] Renamed reserved fields in ntfsrecover the same way as in logfile.h Prepare merging ntfsrecover.h into logfile.h by naming reserved fields the same way. --- ntfsprogs/ntfsrecover.c | 14 +++++++------- ntfsprogs/ntfsrecover.h | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index 3f78bede..cfc8d3a1 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -2156,9 +2156,9 @@ static void showlogr(CONTEXT *ctx, int k, const LOG_RECORD *logr) printf("log_record_flags %04x\n", (int)le16_to_cpu(logr->log_record_flags)); printf("reserved1 %04x %04x %04x\n", - (int)le16_to_cpu(logr->reserved1[0]), - (int)le16_to_cpu(logr->reserved1[1]), - (int)le16_to_cpu(logr->reserved1[2])); + (int)le16_to_cpu(logr->reserved_or_alignment[0]), + (int)le16_to_cpu(logr->reserved_or_alignment[1]), + (int)le16_to_cpu(logr->reserved_or_alignment[2])); detaillogr(ctx, logr); } if (optt) { @@ -2387,9 +2387,9 @@ static void showheadrcrd(u32 blk, const RECORD_PAGE_HEADER *rph) printf("next_record_offset %04x\n", (int)le16_to_cpu(rph->next_record_offset)); printf("reserved4 %04x %04x %04x\n", - (int)le16_to_cpu(rph->reserved4[0]), - (int)le16_to_cpu(rph->reserved4[1]), - (int)le16_to_cpu(rph->reserved4[2])); + (int)le16_to_cpu(rph->reserved[0]), + (int)le16_to_cpu(rph->reserved[1]), + (int)le16_to_cpu(rph->reserved[2])); diff = sle64_to_cpu(rph->last_end_lsn) - synced_lsn; printf("last_end_lsn %016llx (synced%s%ld)\n", (long long)sle64_to_cpu(rph->last_end_lsn), @@ -4068,7 +4068,7 @@ static BOOL checkstructs(void) (int)sizeof(RESTART_PAGE_HEADER)); ok = FALSE; } - if (sizeof(RESTART_AREA) != 44) { + if (sizeof(RESTART_AREA) != 48) { fprintf(stderr, "* error : bad sizeof(RESTART_AREA) %d\n", (int)sizeof(RESTART_AREA)); diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index fec74ed3..a43feef4 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -157,6 +157,7 @@ typedef struct { /* size 44 */ le16 log_record_header_length; le16 log_page_data_offset; le32 restart_log_open_count; + le32 reserved; } __attribute__((__packed__)) RESTART_AREA; typedef struct { /* size 160 */ @@ -208,7 +209,7 @@ typedef struct { /* size 40 */ le16 page_count; le16 page_position; le16 next_record_offset; - le16 reserved4[3]; + le16 reserved[3]; leLSN last_end_lsn; } __attribute__((__packed__)) RECORD_PAGE_HEADER; @@ -228,7 +229,7 @@ typedef struct { /* size 80 */ LOG_RECORD_TYPE record_type; le32 transaction_id; LOG_RECORD_FLAGS log_record_flags; - le16 reserved1[3]; + le16 reserved_or_alignment[3]; le16 redo_operation; le16 undo_operation; le16 redo_offset; From 9693dd2fc1749c14331832b7cfa98c059c3c72b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:58:25 +0200 Subject: [PATCH 23/86] Added a usn field to RESTART_PAGE_HEADER Prepare merging ntfsrecover.h into logfile.h by adding a usn field to RESTART_PAGE_HEADER. As this changes the record size, ignore the new field in existing code. --- include/ntfs-3g/logfile.h | 3 ++- libntfs-3g/logfile.c | 4 ++-- ntfsprogs/ntfsdump_logfile.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/ntfs-3g/logfile.h b/include/ntfs-3g/logfile.h index 6b2305b7..8ce7307b 100644 --- a/include/ntfs-3g/logfile.h +++ b/include/ntfs-3g/logfile.h @@ -93,7 +93,8 @@ typedef struct { version is 1. */ /* 28*/ sle16 major_ver; /* Log file major version. We only support version 1.1. */ -/* sizeof() = 30 (0x1e) bytes */ +/* 30*/ le16 usn; +/* sizeof() = 32 (0x20) bytes */ } __attribute__((__packed__)) RESTART_PAGE_HEADER; /* diff --git a/libntfs-3g/logfile.c b/libntfs-3g/logfile.c index dfe5b7d4..adc0557f 100644 --- a/libntfs-3g/logfile.c +++ b/libntfs-3g/logfile.c @@ -119,7 +119,7 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos) /* Verify the position of the update sequence array. */ usa_ofs = le16_to_cpu(rp->usa_ofs); usa_end = usa_ofs + usa_count * sizeof(u16); - if (usa_ofs < sizeof(RESTART_PAGE_HEADER) || + if (usa_ofs < offsetof(RESTART_PAGE_HEADER, usn) || usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) { ntfs_log_error("$LogFile restart page specifies " "inconsistent update sequence array offset.\n"); @@ -134,7 +134,7 @@ skip_usa_checks: */ ra_ofs = le16_to_cpu(rp->restart_area_offset); if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end : - ra_ofs < sizeof(RESTART_PAGE_HEADER)) || + ra_ofs < offsetof(RESTART_PAGE_HEADER, usn)) || ra_ofs > logfile_system_page_size) { ntfs_log_error("$LogFile restart page specifies " "inconsistent restart area offset.\n"); diff --git a/ntfsprogs/ntfsdump_logfile.c b/ntfsprogs/ntfsdump_logfile.c index f300a5fc..074f87ef 100644 --- a/ntfsprogs/ntfsdump_logfile.c +++ b/ntfsprogs/ntfsdump_logfile.c @@ -319,7 +319,7 @@ static void restart_header_sanity(RESTART_PAGE_HEADER *rstr, u8 *buf) log_err_exit(buf, "Restart page header in $LogFile is " "corrupt: Update sequence array size is " "wrong. Cannot handle this yet.\n"); - if (le16_to_cpu(rstr->usa_ofs) < sizeof(RESTART_PAGE_HEADER)) + if (le16_to_cpu(rstr->usa_ofs) < offsetof(RESTART_PAGE_HEADER, usn)) log_err_exit(buf, "Restart page header in $LogFile is " "corrupt: Update sequence array overlaps " "restart page header. Cannot handle this " From 3cc22ba329a9b915a4df3bc821a1b56c89872e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 11:03:31 +0200 Subject: [PATCH 24/86] Moved general declarations from ntfsrecover.h to logfile.h The declarations related to the log file structure are now grouped in logfile.h, those specific to the recovery process are kept in ntfsrecover.h --- include/ntfs-3g/logfile.h | 119 +++++++++++++++---- ntfsprogs/ntfsdump_logfile.c | 18 +-- ntfsprogs/ntfsrecover.c | 6 +- ntfsprogs/ntfsrecover.h | 221 +---------------------------------- ntfsprogs/playlog.c | 3 +- 5 files changed, 112 insertions(+), 255 deletions(-) diff --git a/include/ntfs-3g/logfile.h b/include/ntfs-3g/logfile.h index 8ce7307b..d1f1222a 100644 --- a/include/ntfs-3g/logfile.h +++ b/include/ntfs-3g/logfile.h @@ -2,6 +2,7 @@ * logfile.h - Exports for $LogFile handling. Originated from the Linux-NTFS project. * * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2016 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -102,8 +103,8 @@ typedef struct { * in this particular client array. Also inside the client records themselves, * this means that there are no client records preceding or following this one. */ -#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff) #define LOGFILE_NO_CLIENT_CPU 0xffff +#define LOGFILE_NO_CLIENT const_cpu_to_le16(LOGFILE_NO_CLIENT_CPU) /* * These are the so far known RESTART_AREA_* flags (16-bit) which contain @@ -322,22 +323,23 @@ typedef struct { le32 flags; le16 page_count; le16 page_position; - union { - struct { - le16 next_record_offset; - u8 reserved[6]; - leLSN last_end_lsn; - } __attribute__((__packed__)) packed; - } __attribute__((__packed__)) header; + le16 next_record_offset; + le16 reserved[3]; + leLSN last_end_lsn; } __attribute__((__packed__)) RECORD_PAGE_HEADER; /** * enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records. * + * Some flags describe what kind of update is being logged. + * * (Or is it log record pages?) */ typedef enum { LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */ + /* The flags below were introduced in Windows 10 */ + LOG_RECORD_DELETING = const_cpu_to_le16(0x0002), + LOG_RECORD_ADDING = const_cpu_to_le16(0x0004), LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff, /* This has nothing to do with the log record. It is only so gcc knows to make the flags 16-bit. */ @@ -351,6 +353,32 @@ typedef struct { le16 client_index; } __attribute__((__packed__)) LOG_CLIENT_ID; +/* + * LOG_RECORD_TYPE : types of log records + */ + +enum { + LOG_STANDARD = const_cpu_to_le32(1), + LOG_CHECKPOINT = const_cpu_to_le32(2), + LOG_RECORD_TYPE_PLACE_HOLDER = 0xffffffffU +} ; +typedef le32 LOG_RECORD_TYPE; + +/* + * ATTRIBUTE_FLAGS : flags describing the kind of NTFS record + * is being updated. + * These flags were introduced in Vista, only two flags are known? + */ + +enum { + ACTS_ON_MFT = const_cpu_to_le16(2), + ACTS_ON_INDX = const_cpu_to_le16(8), + ATTRIBUTE_FLAGS_PLACE_HOLDER = 0xffff, +} ; +typedef le16 ATTRIBUTE_FLAGS; + +#define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */ + /** * struct LOG_RECORD - Log record header. * @@ -362,32 +390,79 @@ typedef struct { leLSN client_undo_next_lsn; le32 client_data_length; LOG_CLIENT_ID client_id; - le32 record_type; + LOG_RECORD_TYPE record_type; le32 transaction_id; - le16 flags; + LOG_RECORD_FLAGS log_record_flags; le16 reserved_or_alignment[3]; /* Now are at ofs 0x30 into struct. */ le16 redo_operation; le16 undo_operation; le16 redo_offset; le16 redo_length; - le16 undo_offset; - le16 undo_length; - le16 target_attribute; - le16 lcns_to_follow; /* Number of lcn_list entries + union { + struct { + le16 undo_offset; + le16 undo_length; + le16 target_attribute; + le16 lcns_to_follow; /* Number of lcn_list entries following this entry. */ /* Now at ofs 0x40. */ - le16 record_offset; - le16 attribute_offset; - le32 alignment_or_reserved; - leVCN target_vcn; + le16 record_offset; + le16 attribute_offset; + le16 cluster_index; + ATTRIBUTE_FLAGS attribute_flags; + leVCN target_vcn; /* Now at ofs 0x50. */ - struct { /* Only present if lcns_to_follow - is not 0. */ - leLCN lcn; - } __attribute__((__packed__)) lcn_list[0]; + leLCN lcn_list[0]; /* Only present if lcns_to_follow + is not 0. */ + } __attribute__((__packed__)); + struct { + leLSN transaction_lsn; + leLSN attributes_lsn; + leLSN names_lsn; + leLSN dirty_pages_lsn; + le64 unknown_list[0]; + } __attribute__((__packed__)); + } __attribute__((__packed__)); } __attribute__((__packed__)) LOG_RECORD; +/** + * struct BITMAP_ACTION - Bitmap change being logged + */ + +struct BITMAP_ACTION { + le32 firstbit; + le32 count; +} ; + +/** + * struct ATTR - Attribute record. + * + * The format of an attribute record has changed from Windows 10. + * The old format was 44 bytes long, despite having 8 bytes fields, + * and this leads to alignment problems in arrays. + * This problem does not occur in the new format, which is shorter. + * The format being used can generally be determined from size. + */ +typedef struct { /* Format up to Win10 (44 bytes) */ + le64 unknown1; + le64 unknown2; + le64 inode; + leLSN lsn; + le32 unknown3; + le32 type; + le32 unknown4; +} __attribute__((__packed__)) ATTR_OLD; + +typedef struct { /* Format since Win10 (40 bytes) */ + le64 unknown1; + le64 unknown2; + le32 type; + le32 unknown3; + le64 inode; + leLSN lsn; +} __attribute__((__packed__)) ATTR_NEW; + extern BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp); extern BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp); extern int ntfs_empty_logfile(ntfs_attr *na); diff --git a/ntfsprogs/ntfsdump_logfile.c b/ntfsprogs/ntfsdump_logfile.c index 074f87ef..2327cc19 100644 --- a/ntfsprogs/ntfsdump_logfile.c +++ b/ntfsprogs/ntfsdump_logfile.c @@ -557,17 +557,17 @@ static void dump_log_record(LOG_RECORD *lr) (unsigned int)le32_to_cpu(lr->record_type)); ntfs_log_info("transaction_id = 0x%x\n", (unsigned int)le32_to_cpu(lr->transaction_id)); - ntfs_log_info("flags = 0x%x:", le16_to_cpu(lr->flags)); - if (!lr->flags) + ntfs_log_info("flags = 0x%x:", le16_to_cpu(lr->log_record_flags)); + if (!lr->log_record_flags) ntfs_log_info(" NONE\n"); else { int _b = 0; - if (lr->flags & LOG_RECORD_MULTI_PAGE) { + if (lr->log_record_flags & LOG_RECORD_MULTI_PAGE) { ntfs_log_info(" LOG_RECORD_MULTI_PAGE"); _b = 1; } - if (lr->flags & ~LOG_RECORD_MULTI_PAGE) { + if (lr->log_record_flags & ~LOG_RECORD_MULTI_PAGE) { if (_b) ntfs_log_info(" |"); ntfs_log_info(" Unknown flags"); @@ -589,8 +589,8 @@ static void dump_log_record(LOG_RECORD *lr) if (le16_to_cpu(lr->lcns_to_follow) > 0) ntfs_log_info("Array of lcns:\n"); for (i = 0; i < le16_to_cpu(lr->lcns_to_follow); i++) - ntfs_log_info("lcn_list[%u].lcn = 0x%llx\n", i, (unsigned long long) - sle64_to_cpu(lr->lcn_list[i].lcn)); + ntfs_log_info("lcn_list[%u].lcn = 0x%llx\n", i, + (unsigned long long)sle64_to_cpu(lr->lcn_list[i])); } /** @@ -633,9 +633,9 @@ rcrd_pass_loc: ntfs_log_info("page count = %i\n", le16_to_cpu(rcrd->page_count)); ntfs_log_info("page position = %i\n", le16_to_cpu(rcrd->page_position)); ntfs_log_info("header.next_record_offset = 0x%llx\n", (unsigned long long) - le16_to_cpu(rcrd->header.packed.next_record_offset)); + le16_to_cpu(rcrd->next_record_offset)); ntfs_log_info("header.last_end_lsn = 0x%llx\n", (unsigned long long) - sle64_to_cpu(rcrd->header.packed.last_end_lsn)); + sle64_to_cpu(rcrd->last_end_lsn)); /* * Where does the 0x40 come from? Is it just usa_offset + * usa_client * 2 + 7 & ~7 or is it derived from somewhere? @@ -648,7 +648,7 @@ rcrd_pass_loc: client++; lr = (LOG_RECORD*)((u8*)lr + 0x70); } while (((u8*)lr + 0x70 <= (u8*)rcrd + - le16_to_cpu(rcrd->header.packed.next_record_offset))); + le16_to_cpu(rcrd->next_record_offset))); pass++; goto rcrd_pass_loc; diff --git a/ntfsprogs/ntfsrecover.c b/ntfsprogs/ntfsrecover.c index cfc8d3a1..05a1d087 100644 --- a/ntfsprogs/ntfsrecover.c +++ b/ntfsprogs/ntfsrecover.c @@ -1,7 +1,7 @@ /* * Process log data from an NTFS partition * - * Copyright (c) 2012-2015 Jean-Pierre Andre + * Copyright (c) 2012-2016 Jean-Pierre Andre * * This program examines the Windows log file of an ntfs partition * and plays the committed transactions in order to restore the @@ -101,6 +101,7 @@ #include "volume.h" #include "unistr.h" #include "mst.h" +#include "logfile.h" #include "ntfsrecover.h" #include "utils.h" #include "misc.h" @@ -3832,7 +3833,7 @@ static void version(void) { printf("\n%s v%s (libntfs-3g) - Recover updates committed by Windows" " on an NTFS Volume.\n\n", "ntfsrecover", VERSION); - printf("Copyright (c) 2012-2015 Jean-Pierre Andre\n"); + printf("Copyright (c) 2012-2016 Jean-Pierre Andre\n"); printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -3856,7 +3857,6 @@ static void usage(void) fprintf(stderr," -u : undo the latest count transaction sets\n"); fprintf(stderr," -v : show more information (-vv yet more)\n"); fprintf(stderr," -V : show version and exit\n"); - fprintf(stderr," Copyright (c) 2012-2015 Jean-Pierre Andre\n"); } /* diff --git a/ntfsprogs/ntfsrecover.h b/ntfsprogs/ntfsrecover.h index a43feef4..abc72a0f 100644 --- a/ntfsprogs/ntfsrecover.h +++ b/ntfsprogs/ntfsrecover.h @@ -2,7 +2,7 @@ * Declarations for processing log data * * Copyright (c) 2000-2005 Anton Altaparmakov - * Copyright (c) 2014-2015 Jean-Pierre Andre + * Copyright (c) 2014-2016 Jean-Pierre Andre */ /* @@ -22,16 +22,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - * TODO - * This file partially duplicates logfile.h (with modifications). - * The generic declarations are to be moved to logfile.h, thus - * implying adapting (at least) libntfs-3g/logfile.c and - * ntfsprogs/ntfsdump_logfile.c, and the declarations specific to - * ntfsrecover should be kept in this file. - * (removing ntfsdump_logfile.c might also be considered). - */ - #define getle16(p,x) le16_to_cpu(*(const le16*)((const char*)(p) + (x))) #define getle32(p,x) le32_to_cpu(*(const le32*)((const char*)(p) + (x))) #define getle64(p,x) le64_to_cpu(*(const le64*)((const char*)(p) + (x))) @@ -40,30 +30,6 @@ #define feedle32(p,x) (*(const le32*)((const char*)(p) + (x))) #define feedle64(p,x) (*(const le64*)((const char*)(p) + (x))) -/* - * LOG_RECORD_TYPE : types of log records - */ - -enum { - LOG_STANDARD = const_cpu_to_le32(1), - LOG_CHECKPOINT = const_cpu_to_le32(2), - LOG_RECORD_TYPE_PLACE_HOLDER = 0xffffffffU -} ; -typedef le32 LOG_RECORD_TYPE; - -/* - * ATTRIBUTE_FLAGS : flags describing the kind of NTFS record - * is being updated. - * These flags were introduced in Vista, only two flags are known? - */ - -enum { - ACTS_ON_MFT = const_cpu_to_le16(2), - ACTS_ON_INDX = const_cpu_to_le16(8), - ATTRIBUTE_FLAGS_PLACE_HOLDER = 0xffff, -} ; -typedef le16 ATTRIBUTE_FLAGS; - enum ACTIONS { Noop, /* 0 */ CompensationlogRecord, /* 1 */ @@ -106,157 +72,6 @@ enum ACTIONS { LastAction /* 38 */ } ; -/** - * enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records. - * - * Some flags describe what kind of update is being logged. - * - * (Or is it log record pages?) - */ -typedef enum { - LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */ - /* The flags below were introduced in Windows 10 */ - LOG_RECORD_DELETING = const_cpu_to_le16(0x0002), - LOG_RECORD_ADDING = const_cpu_to_le16(0x0004), - LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff, - /* This has nothing to do with the log record. It is only so - gcc knows to make the flags 16-bit. */ -} __attribute__((__packed__)) LOG_RECORD_FLAGS; - -#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff) -#define RESTART_VOLUME_IS_CLEAN const_cpu_to_le16(0x0002) - -/* ntfsdoc p 39 (47), not in layout.h */ - -typedef struct { /* size 32 */ - NTFS_RECORD_TYPES magic; - le16 usa_ofs; - le16 usa_count; - leLSN chkdsk_lsn; - le32 system_page_size; - le32 log_page_size; - le16 restart_area_offset; - le16 minor_ver; - le16 major_ver; - le16 usn; -} __attribute__((__packed__)) RESTART_PAGE_HEADER; - -/* ntfsdoc p 40 (48), not in layout.h */ - -typedef struct { /* size 44 */ - leLSN current_lsn; - le16 log_clients; - le16 client_free_list; - le16 client_in_use_list; - le16 flags; - le32 seq_number_bits; - le16 restart_area_length; - le16 client_array_offset; - le64 file_size; - le32 last_lsn_data_length; - le16 log_record_header_length; - le16 log_page_data_offset; - le32 restart_log_open_count; - le32 reserved; -} __attribute__((__packed__)) RESTART_AREA; - -typedef struct { /* size 160 */ -/*Ofs*/ -/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create - set to 0. */ -/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart - the volume, i.e. the current position within - the log file. At present, if clean this - should = current_lsn in restart area but it - probably also = current_lsn when dirty most - of the time. At create set to 0. */ -/* 16*/ le16 prev_client; /* The offset to the previous log client record - in the array of log client records. - LOGFILE_NO_CLIENT means there is no previous - client record, i.e. this is the first one. - This is always LOGFILE_NO_CLIENT. */ -/* 18*/ le16 next_client; /* The offset to the next log client record in - the array of log client records. - LOGFILE_NO_CLIENT means there are no next - client records, i.e. this is the last one. - This is always LOGFILE_NO_CLIENT. */ -/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set - to zero every time the logfile is restarted - and it is incremented when the logfile is - closed at dismount time. Thus it is 0 when - dirty and 1 when clean. On WinXP and - presumably later, this is always 0. */ -/* 22*/ u8 reserved[6]; /* Reserved/alignment. */ -/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should - always be 8. */ -/* 32*/ le16 client_name[64]; /* Name of the client in Unicode. Should - always be "NTFS" with the remaining bytes - set to 0. */ -/* sizeof() = 160 (0xa0) bytes */ -} __attribute__((__packed__)) LOG_CLIENT_RECORD; - -/* ntfsdoc p 41 (49), not in layout.h */ - -typedef struct { /* size 40 */ - NTFS_RECORD_TYPES magic; - le16 usa_ofs; - le16 usa_count; - union { - leLSN last_lsn; - sle64 file_offset; - } __attribute__((__packed__)) copy; - le32 flags; - le16 page_count; - le16 page_position; - le16 next_record_offset; - le16 reserved[3]; - leLSN last_end_lsn; -} __attribute__((__packed__)) RECORD_PAGE_HEADER; - -/* ntfsdoc p 42 (50), not in layout.h */ - -#define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */ - -typedef struct { /* size 80 */ - leLSN this_lsn; - leLSN client_previous_lsn; - leLSN client_undo_next_lsn; - le32 client_data_length; - struct { - le16 seq_number; - le16 client_index; - } __attribute__((__packed__)) client_id; - LOG_RECORD_TYPE record_type; - le32 transaction_id; - LOG_RECORD_FLAGS log_record_flags; - le16 reserved_or_alignment[3]; - le16 redo_operation; - le16 undo_operation; - le16 redo_offset; - le16 redo_length; - union { - struct { - le16 undo_offset; - le16 undo_length; - le16 target_attribute; - le16 lcns_to_follow; - le16 record_offset; - le16 attribute_offset; - le16 cluster_index; - ATTRIBUTE_FLAGS attribute_flags; - leVCN target_vcn; - le64 lcn_list[0]; - } __attribute__((__packed__)); - struct { - leLSN transaction_lsn; - leLSN attributes_lsn; - leLSN names_lsn; - leLSN dirty_pages_lsn; - le64 unknown_list[0]; - } __attribute__((__packed__)); - } __attribute__((__packed__)); -} __attribute__((__packed__)) LOG_RECORD; - struct BUFFER { unsigned int num; unsigned int size; @@ -290,39 +105,6 @@ struct ATTR { le16 name[1]; } ; -struct BITMAP_ACTION { - le32 firstbit; - le32 count; -} ; - -/** - * struct ATTR - Attribute record. - * - * The format of an attribute record has changed from Windows 10. - * The old format was 44 bytes long, despite having 8 bytes fields, - * and this leads to alignment problems in arrays. - * This problem does not occur in the new format, which is shorter. - * The format being used can generally be determined from size. - */ -typedef struct { /* Format up to Win10 (44 bytes) */ - le64 unknown1; - le64 unknown2; - le64 inode; - leLSN lsn; - le32 unknown3; - le32 type; - le32 unknown4; -} __attribute__((__packed__)) ATTR_OLD; - -typedef struct { /* Format since Win10 (40 bytes) */ - le64 unknown1; - le64 unknown2; - le32 type; - le32 unknown3; - le64 inode; - leLSN lsn; -} __attribute__((__packed__)) ATTR_NEW; - extern u32 clustersz; extern int clusterbits; extern u32 blocksz; @@ -364,7 +146,6 @@ u32 get_extra_offset(const LOG_RECORD *logr); BOOL exception(int num); struct STORE; -BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp); extern int play_undos(ntfs_volume *vol, const struct ACTION_RECORD *firstundo); extern int play_redos(ntfs_volume *vol, const struct ACTION_RECORD *firstredo); extern void show_redos(void); diff --git a/ntfsprogs/playlog.c b/ntfsprogs/playlog.c index 40781462..8bc5cf2f 100644 --- a/ntfsprogs/playlog.c +++ b/ntfsprogs/playlog.c @@ -1,7 +1,7 @@ /* * Redo or undo a list of logged actions * - * Copyright (c) 2014-2015 Jean-Pierre Andre + * Copyright (c) 2014-2016 Jean-Pierre Andre * */ @@ -67,6 +67,7 @@ #include "volume.h" #include "unistr.h" #include "mst.h" +#include "logfile.h" #include "ntfsrecover.h" #include "misc.h" From 18a66b7a9a0ebc9f07498a0f18fd96667f9023e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 11:07:30 +0200 Subject: [PATCH 25/86] Fixed a spelling error in ntfsresize manual (cosmetic) an other -> another --- ntfsprogs/ntfsresize.8.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsresize.8.in b/ntfsprogs/ntfsresize.8.in index 177eb500..2ee53460 100644 --- a/ntfsprogs/ntfsresize.8.in +++ b/ntfsprogs/ntfsresize.8.in @@ -88,7 +88,7 @@ To enlarge an NTFS filesystem, first you must enlarge the size of the underlying partition. This can be done using .BR fdisk (8) by deleting the partition and recreating it with a larger size. -Make sure it will not overlap with an other existing partition. +Make sure it will not overlap with another existing partition. You may enlarge upwards (first sector unchanged) or downwards (last sector unchanged), but you may not enlarge at both ends in a single step. If you merge two NTFS partitions, only one of them can be expanded to the From 7917a0a6cc0053c81bbdac2fcf714fdcd652c82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 11:09:35 +0200 Subject: [PATCH 26/86] Fixed indentation in ntfsclone help text (cosmetic) The tabs in source code appear differently in actual output. --- ntfsprogs/ntfsclone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 4ccb0168..60264c9d 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -374,7 +374,7 @@ static void usage(int ret) #ifdef DEBUG " -d, --debug Show debug information\n" #endif - " -V, --version Display version information\n" + " -V, --version Display version information\n" "\n" " If FILE is '-' then send the image to the standard output. If SOURCE is '-'\n" " and --restore-image is used then read the image from the standard input.\n" From 0ded128808350043b53557d980414e7148bd7a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Thu, 7 Apr 2016 09:07:13 +0200 Subject: [PATCH 27/86] Moved secaudit and usermap to directory ntfsprogs These tools were developped before the ntfsprogs were merged into ntfs-3g, redesigning them like the ntfsprogs make the code simpler. Note : at this stage secaudit and usermap cannot be built any more. --- src/ntfs-3g.secaudit.8.in => ntfsprogs/ntfssecaudit.8.in | 0 src/secaudit.c => ntfsprogs/ntfssecaudit.c | 0 src/ntfs-3g.usermap.8.in => ntfsprogs/ntfsusermap.8.in | 0 src/usermap.c => ntfsprogs/ntfsusermap.c | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/ntfs-3g.secaudit.8.in => ntfsprogs/ntfssecaudit.8.in (100%) rename src/secaudit.c => ntfsprogs/ntfssecaudit.c (100%) rename src/ntfs-3g.usermap.8.in => ntfsprogs/ntfsusermap.8.in (100%) rename src/usermap.c => ntfsprogs/ntfsusermap.c (100%) diff --git a/src/ntfs-3g.secaudit.8.in b/ntfsprogs/ntfssecaudit.8.in similarity index 100% rename from src/ntfs-3g.secaudit.8.in rename to ntfsprogs/ntfssecaudit.8.in diff --git a/src/secaudit.c b/ntfsprogs/ntfssecaudit.c similarity index 100% rename from src/secaudit.c rename to ntfsprogs/ntfssecaudit.c diff --git a/src/ntfs-3g.usermap.8.in b/ntfsprogs/ntfsusermap.8.in similarity index 100% rename from src/ntfs-3g.usermap.8.in rename to ntfsprogs/ntfsusermap.8.in diff --git a/src/usermap.c b/ntfsprogs/ntfsusermap.c similarity index 100% rename from src/usermap.c rename to ntfsprogs/ntfsusermap.c From 3d7a28bfa5bcdf7669270f3afca5e672c46f7c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Thu, 7 Apr 2016 09:20:23 +0200 Subject: [PATCH 28/86] Adapted secaudit and usermap (now ntfssecaudit and ntfsusermap) to ntfsprogs These tools were originally developed for running on Windows and later ported to libntfs-3g. This patch makes them similar to other ntfsprogs tools, dropping the native Windows interfaces and using libntfs-3g on all platforms. There is no change in usage or supported features, only the command names have changed. --- configure.ac | 4 +- ntfsprogs/Makefile.am | 14 +- ntfsprogs/ntfssecaudit.8.in | 22 +- ntfsprogs/ntfssecaudit.c | 3934 ++++++++++++----------------------- ntfsprogs/ntfsusermap.8.in | 24 +- ntfsprogs/ntfsusermap.c | 957 ++++----- src/Makefile.am | 18 +- src/ntfs-3g.8.in | 2 +- 8 files changed, 1685 insertions(+), 3290 deletions(-) diff --git a/configure.ac b/configure.ac index b14b00af..644ae00a 100644 --- a/configure.ac +++ b/configure.ac @@ -668,11 +668,11 @@ AC_CONFIG_FILES([ ntfsprogs/ntfstruncate.8 ntfsprogs/ntfsfallocate.8 ntfsprogs/ntfsrecover.8 + ntfsprogs/ntfsusermap.8 + ntfsprogs/ntfssecaudit.8 src/Makefile src/ntfs-3g.8 src/ntfs-3g.probe.8 - src/ntfs-3g.usermap.8 - src/ntfs-3g.secaudit.8 ]) AC_OUTPUT diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 0bbc70c5..f4f9d1b6 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -17,7 +17,8 @@ if ENABLE_NTFSPROGS bin_PROGRAMS = ntfsfix ntfsinfo ntfscluster ntfsls ntfscat ntfscmp sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize ntfsclone \ ntfscp -EXTRA_PROGRAM_NAMES = ntfswipe ntfstruncate ntfsrecover +EXTRA_PROGRAM_NAMES = ntfswipe ntfstruncate ntfsrecover \ + ntfsusermap ntfssecaudit QUARANTINED_PROGRAM_NAMES = ntfsdump_logfile ntfsmftalloc ntfsmove ntfsck \ ntfsfallocate @@ -26,7 +27,8 @@ man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8 \ ntfsundelete.8 ntfsresize.8 ntfsprogs.8 ntfsls.8 \ ntfsclone.8 ntfscluster.8 ntfscat.8 ntfscp.8 \ ntfscmp.8 ntfswipe.8 ntfstruncate.8 \ - ntfsdecrypt.8 ntfsfallocate.8 ntfsrecover.8 + ntfsdecrypt.8 ntfsfallocate.8 ntfsrecover.8 \ + ntfsusermap.8 ntfssecaudit.8 EXTRA_MANS = CLEANFILES = $(EXTRA_PROGRAMS) @@ -106,6 +108,14 @@ ntfsrecover_SOURCES = playlog.c ntfsrecover.c utils.c utils.h ntfsrecover.h ntfsrecover_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS) ntfsrecover_LDFLAGS = $(AM_LFLAGS) +ntfsusermap_SOURCES = ntfsusermap.c utils.c utils.h +ntfsusermap_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS) +ntfsusermap_LDFLAGS = $(AM_LFLAGS) + +ntfssecaudit_SOURCES = ntfssecaudit.c utils.c utils.h +ntfssecaudit_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS) +ntfssecaudit_LDFLAGS = $(AM_LFLAGS) + # We don't distribute these ntfstruncate_SOURCES = attrdef.c ntfstruncate.c utils.c utils.h diff --git a/ntfsprogs/ntfssecaudit.8.in b/ntfsprogs/ntfssecaudit.8.in index 669828e5..b715f4d9 100644 --- a/ntfsprogs/ntfssecaudit.8.in +++ b/ntfsprogs/ntfssecaudit.8.in @@ -1,11 +1,11 @@ -.\" Copyright (c) 2007-2009 Jean-Pierre André. +.\" Copyright (c) 2007-2016 Jean-Pierre André. .\" This file may be copied under the terms of the GNU Public License. .\" -.TH NTFS-3G.SECAUDIT 8 "February 2010" "ntfs-3g.secaudit 1.4.1" +.TH NTFSSECAUDIT 8 "February 2010" "ntfssecaudit 1.5.0" .SH NAME -ntfs-3g.secaudit \- NTFS Security Data Auditing +ntfssecaudit \- NTFS Security Data Auditing .SH SYNOPSIS -.B ntfs-3g.secaudit +.B ntfssecaudit \fB[\fIoptions\fP\fB]\fR .I args .PP @@ -39,7 +39,7 @@ and args define the parameters and the set of files acted upon. .PP Typing secaudit with no args will display a summary of available options. .SH DESCRIPTION -\fBntfs-3g.secaudit\fR +\fBntfssecaudit\fR displays the ownership and permissions of a set of files on an NTFS file system, and checks their consistency. It can be started in terminal mode only (no graphical user interface is available.) @@ -53,7 +53,7 @@ of information. It is therefore advisable to redirect the output to a file or pipe it to a text editor for examination. .SH OPTIONS Below are the valid combinations of options and arguments that -\fBntfs-3g.secaudit\fR accepts. All the indicated arguments are +\fBntfssecaudit\fR accepts. All the indicated arguments are mandatory and must be unique (if wildcards are used, they must resolve to a single name.) .TP @@ -135,25 +135,25 @@ Example : "\fBu::7,g::5,o:0,u:510:rwx,g:500:5,d:u:510:7\fP" Audit the global security data on /dev/sda1 .RS .sp -.B ntfs-3g.secaudit -ar /dev/sda1 +.B ntfssecaudit -ar /dev/sda1 .sp .RE Display the ownership and permissions parameters for files in directory /audio/music on device /dev/sda5, excluding sub-directories : .RS .sp -.B ntfs-3g.secaudit /dev/sda5 /audio/music +.B ntfssecaudit /dev/sda5 /audio/music .sp .RE Set all files in directory /audio/music on device /dev/sda5 as writeable by owner and read-only for everybody : .RS .sp -.B ntfs-3g.secaudit -r /dev/sda5 644 /audio/music +.B ntfssecaudit -r /dev/sda5 644 /audio/music .sp .RE .SH EXIT CODES -.B ntfs-3g.secaudit +.B ntfssecaudit exits with a value of 0 when no error was detected, and with a value of 1 when an error was detected. .SH KNOWN ISSUES @@ -170,7 +170,7 @@ in detail. You can contact the development team on the ntfs\-3g\-devel@lists.sf.net address. .SH AUTHORS -.B ntfs-3g.secaudit +.B ntfssecaudit has been developed by Jean-Pierre André. .SH THANKS Several people made heroic efforts, often over five or more diff --git a/ntfsprogs/ntfssecaudit.c b/ntfsprogs/ntfssecaudit.c index 29236c6d..abd5bfd5 100644 --- a/ntfsprogs/ntfssecaudit.c +++ b/ntfsprogs/ntfssecaudit.c @@ -1,8 +1,8 @@ /* * Display and audit security attributes in an NTFS volume * - * Copyright (c) 2007-2015 Jean-Pierre Andre - * + * Copyright (c) 2007-2016 Jean-Pierre Andre + * * Options : * -a auditing security data * -b backing up NTFS ACLs @@ -33,21 +33,25 @@ * set the security parameters of file to perms (mode or acl) * secaudit -r[v] volume perms directory * set the security parameters of files in directory to perms - * special case, does not require being root : + * special cases, do not require being root : * secaudit [-v] mounted-file * display the security parameters of mounted file + * secaudit -u[v] mounted-file + * display a user mapping proposal * * * On Windows (the volume being part of file name) * secaudit -h [file] * display the security descriptors found in file + * secaudit -a[rv] volume + * audit the volume * secaudit [-v] file * display the security parameters of file * secaudit -r[v] directory * display the security parameters of files in directory * secaudit -b[v] directory * backup the security parameters of files in directory - * secaudit -s[v] [backupfile] + * secaudit -s[v] volume [backupfile] * set the security parameters as indicated in backup * with -e set extra parameters (Windows attrib) * secaudit perms file @@ -221,6 +225,9 @@ * * May 2015, version 1.4.6 * - made to load shared library based on generic name + * + * Mar 2016, Version 1.5.0 + * - reorganized to rely on libntfs-3g even on Windows */ /* @@ -244,312 +251,202 @@ * General parameters which may have to be adapted to needs */ -#define AUDT_VERSION "1.4.6" +#define AUDT_VERSION "1.5.0" -#define GET_FILE_SECURITY "ntfs_get_file_security" -#define SET_FILE_SECURITY "ntfs_set_file_security" -#define GET_FILE_ATTRIBUTES "ntfs_get_file_attributes" -#define SET_FILE_ATTRIBUTES "ntfs_set_file_attributes" -#define READ_DIRECTORY "ntfs_read_directory" -#define READ_SDS "ntfs_read_sds" -#define READ_SII "ntfs_read_sii" -#define READ_SDH "ntfs_read_sdh" -#define GET_USER "ntfs_get_user" -#define GET_GROUP "ntfs_get_group" -#define GET_USID "ntfs_get_usid" -#define GET_GSID "ntfs_get_gsid" -#define INIT_FILE_SECURITY "ntfs_initialize_file_security" -#define LEAVE_FILE_SECURITY "ntfs_leave_file_security" +#define SELFTESTS 0 +#define NOREVBOM 0 /* still unclear what this should be */ /* * External declarations */ -#include -#include -#include -#include -#include -#include -#include -#include - - /* - * integration into secaudit, check whether Win32, - * may have to be adapted to compiler or something else - */ - -#ifndef WIN32 -#if defined(__WIN32) | defined(__WIN32__) | defined(WNSC) -#define WIN32 1 -#endif -#endif - - /* - * integration into secaudit/Win32 - */ -#ifdef WIN32 -#include -#define __LITTLE_ENDIAN 1234 -#define __BYTE_ORDER __LITTLE_ENDIAN -#else - /* - * integration into secaudit/STSC - */ -#ifdef STSC -#include -#undef __BYTE_ORDER -#define __BYTE_ORDER __BIG_ENDIAN -#else - /* - * integration into secaudit/Linux - */ - -#include -#ifdef HAVE_ENDIAN_H -#include -#endif -#ifdef HAVE_MACHINE_ENDIAN_H -#include -#endif -#include -#include -#endif /* STSC */ -#endif /* WIN32 */ -#include "secaudit.h" - -#ifndef WIN32 - -#ifndef STSC - -#if !defined(HAVE_CONFIG_H) && POSIXACLS && !defined(__SVR4) - /* require if not integrated into ntfs-3g package */ -#define HAVE_SETXATTR 1 -#endif - -#ifdef HAVE_CONFIG_H -#ifdef _FILE_OFFSET_BITS -#undef _FILE_OFFSET_BITS /* work around "_FILE_OFFSET_BITS" possibly already defined */ -#endif - /* according to config.h if integrated into ntfs-3g package */ #include "config.h" -#ifdef const /* work around "const" possibly redefined in config.h */ -#undef const -#endif -#ifndef POSIXACLS -#define POSIXACLS 0 -#endif -#endif /* HAVE_CONFIG_H */ +#ifdef HAVE_STDIO_H +#include +#endif /* HAVE_STDIO_H */ +#ifdef HAVE_STDLIB_H +#include +#endif /* HAVE_STDLIB_H */ +#ifdef HAVE_STRING_H +#include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_TIME_H +#include +#endif /* HAVE_TIME_H */ +#ifdef HAVE_GETOPT_H +#include +#endif /* HAVE_GETOPT_H */ +#ifdef HAVE_ERRNO_H +#include +#endif /* HAVE_ERRNO_H */ +#ifdef HAVE_FCNTL_H +#include +#endif /* HAVE_FCNTL_H */ +#ifdef HAVE_SYS_TYPES_H +#include +#endif /* HAVE_SYS_TYPES_H */ +#ifdef HAVE_SYS_STAT_H +#include +#endif /* HAVE_SYS_STAT_H */ #ifdef HAVE_SETXATTR #include -#else +#else /* HAVE_SETXATTR */ #warning "The extended attribute package is not available" #endif /* HAVE_SETXATTR */ -#endif /* STSC */ - -#define NTFS_MNT_NONE 0 /* no flag for mounting the device */ -#define NTFS_MNT_RDONLY 1 /* flag for mounting the device read-only */ +#include "types.h" +#include "endians.h" +#include "support.h" +#include "layout.h" +#include "param.h" +#include "ntfstime.h" +#include "device_io.h" +#include "device.h" +#include "logging.h" +#include "runlist.h" +#include "mft.h" +#include "inode.h" +#include "attrib.h" +#include "bitmap.h" +#include "index.h" +#include "volume.h" +#include "unistr.h" +#include "mst.h" +#include "security.h" +#include "acls.h" +#include "realpath.h" +#include "utils.h" +#include "misc.h" struct CALLBACK; -typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname, - int length, int type, long long pos, u64 mft_ref, - unsigned int dt_type); +typedef int (*dircallback)(void *context, const ntfschar *ntfsname, + const int length, const int type, const s64 pos, + const MFT_REF mft_ref, const unsigned int dt_type); + +#if POSIXACLS + +static BOOL same_posix(struct POSIX_SECURITY *pxdesc1, + struct POSIX_SECURITY *pxdesc2); + +#endif /* POSIXACLS */ #ifndef HAVE_SYSLOG_H void ntfs_log_early_error(const char *format, ...) __attribute__((format(printf, 1, 2))); -#endif - -#if USESTUBS | defined(STSC) - -int ntfs_get_file_security(void *scapi, - const char *path, DWORD selection, - char *buf, DWORD buflen, LPDWORD psize); -BOOL ntfs_set_file_security(void *scapi, - const char *path, DWORD selection, const char *attr); -int ntfs_get_file_attributes(void *scapi, - const char *path); -BOOL ntfs_set_file_attributes(void *scapi, - const char *path, DWORD attrib); -BOOL ntfs_read_directory(void *scapi, - const char *path, dircallback callback, void *context); -int ntfs_read_sds(void *scapi, - char *buf, DWORD buflen, DWORD offset); -void *ntfs_read_sii(void *scapi, void *entry); -void *ntfs_read_sdh(void *scapi, void *entry); - -int ntfs_get_usid(void *scapi, uid_t uid, char *buf); -int ntfs_get_gsid(void *scapi, gid_t gid, char *buf); -int ntfs_get_user(void *scapi, const char *usid); -int ntfs_get_group(void *scapi, const char *gsid); - -void *ntfs_initialize_file_security(const char *device, unsigned long flags); -BOOL ntfs_leave_file_security(void *scapi); - -#else - -typedef int (*type_get_file_security)(void *scapi, - const char *path, DWORD selection, - char *buf, DWORD buflen, LPDWORD psize); -typedef BOOL (*type_set_file_security)(void *scapi, - const char *path, DWORD selection, const char *attr); -typedef int (*type_get_file_attributes)(void *scapi, - const char *path); -typedef BOOL (*type_set_file_attributes)(void *scapi, - const char *path, DWORD attrib); -typedef BOOL (*type_read_directory)(void *scapi, - const char *path, dircallback callback, void *context); -typedef int (*type_read_sds)(void *scapi, - char *buf, DWORD buflen, DWORD offset); -typedef void *(*type_read_sii)(void *scapi, void *entry); -typedef void *(*type_read_sdh)(void *scapi, void *entry); - -typedef int (*type_get_usid)(void *scapi, uid_t uid, char *buf); -typedef int (*type_get_gsid)(void *scapi, gid_t gid, char *buf); -typedef int (*type_get_user)(void *scapi, const char *usid); -typedef int (*type_get_group)(void *scapi, const char *gsid); - -typedef void *(*type_initialize_file_security)(const char *device, - unsigned long flags); -typedef BOOL (*type_leave_file_security)(void *scapi); - -type_get_file_security ntfs_get_file_security; -type_set_file_security ntfs_set_file_security; -type_get_file_attributes ntfs_get_file_attributes; -type_set_file_attributes ntfs_set_file_attributes; -type_read_directory ntfs_read_directory; -type_read_sds ntfs_read_sds; -type_read_sii ntfs_read_sii; -type_read_sdh ntfs_read_sdh; - -type_get_usid ntfs_get_usid; -type_get_gsid ntfs_get_gsid; -type_get_user ntfs_get_user; -type_get_group ntfs_get_group; - -type_initialize_file_security ntfs_initialize_file_security; -type_leave_file_security ntfs_leave_file_security; - - -#endif /* USESTUBS | defined(STSC) */ -#endif /* WIN32 */ +#endif /* HAVE_SYSLOG_H */ #define ACCOUNTSIZE 256 /* maximum size of an account name */ +#define MAXFILENAME 4096 +#define MAXATTRSZ 65536 /* Max sec attr size (16448 met for WinXP) */ +#define MAXLINE 80 /* maximum processed size of a line */ +#define BUFSZ 1024 /* buffer size to read mapping file */ +#define LINESZ 120 /* maximum useful size of a mapping line */ + +typedef enum { RECSHOW, RECSET, RECSETPOSIX } RECURSE; +typedef enum { MAPNONE, MAPEXTERN, MAPLOCAL, MAPDUMMY } MAPTYPE; +typedef enum { CMD_AUDIT, CMD_BACKUP, CMD_HEX, CMD_HELP, CMD_SET, + CMD_TEST, CMD_USERMAP, CMD_VERSION, CMD_NONE } CMDS; + + +#define MAXSECURID 262144 +#define SECBLKSZ 8 +#define MAPDIR ".NTFS-3G" +#define MAPFILE "UserMapping" + +#ifdef HAVE_WINDOWS_H +#define DIRSEP "\\" +#else +#define DIRSEP "/" +#endif + + /* standard owner (and administrator) rights */ + +#define OWNER_RIGHTS (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER \ + | SYNCHRONIZE \ + | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \ + | FILE_READ_EA | FILE_WRITE_EA) + + /* standard world rights */ + +#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \ + | SYNCHRONIZE) + + /* inheritance flags for files and directories */ + +#define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE +#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE) /* - * Prototypes for local functions + * To identify NTFS ACL meaning Posix ACL granted to root + * we use rights always granted to anybody, so they have no impact + * either on Windows or on Linux. */ -BOOL open_security_api(void); -BOOL close_security_api(void); -#ifndef WIN32 -BOOL open_volume(const char*, unsigned long flags); -BOOL close_volume(const char*); -#endif -unsigned int get2l(const char*, int); -unsigned long get4l(const char*, int); -u64 get6l(const char*, int); -u64 get6h(const char*, int); -u64 get8l(const char*, int); -void set2l(char*, unsigned int); -void set4l(char*, unsigned long); -void hexdump(const char*, int, int); -u32 hash(const le32*, int); -unsigned int utf8size(const char*, int); -unsigned int makeutf8(char*, const char*, int); -unsigned int utf16size(const char*); -unsigned int makeutf16(char*, const char*); -unsigned int utf16len(const char*); -void printname(FILE*, const char*); -void printerror(FILE*); -BOOL guess_dir(const char*); -void showsid(const char*, int, const char*, int); -void showusid(const char*, int); -void showgsid(const char*, int); -void showownership(const char*); -void showheader(const char*, int); -void showace(const char*, int, int, int); -void showacl(const char*, int, int, int); -void showdacl(const char*, int, int); -void showsacl(const char*, int, int); -void showall(const char*, int); -void showposix(const struct POSIX_SECURITY*); -int linux_permissions(const char*, BOOL); -uid_t linux_owner(const char*); -gid_t linux_group(const char*); -int basicread(void*, char*, size_t, off_t); -int dummyread(void*, char*, size_t, off_t); -int local_build_mapping(struct MAPPING *[], const char*); -void newblock(s32); -void freeblocks(void); -u32 getmsbhex(const char*); -u32 getlsbhex(const char*); -BOOL ishexdump(const char*, int, int); -void showhex(FILE*); -void showfull(const char*, BOOL); -BOOL applyattr(const char*, const char*, BOOL, int, s32); -BOOL restore(FILE*); -BOOL dorestore(const char*, FILE*); -u32 merge_rights(const struct POSIX_SECURITY*, BOOL); -void tryposix(struct POSIX_SECURITY*); -void check_samples(void); -void basictest(int, BOOL, const SID*, const SID*); -void posixtest(int, BOOL, const SID*, const SID*); -void selftests(void); -unsigned int getfull(char*, const char*); -BOOL updatefull(const char *name, DWORD flags, char *attr); -BOOL setfull(const char*, int, BOOL); -BOOL singleshow(const char*); -BOOL proposal(const char*, const char*); -BOOL showmounted(const char*); -BOOL processmounted(const char*); -BOOL recurseshow(const char*); -BOOL singleset(const char*, int); -BOOL recurseset(const char*, int); -#ifdef WIN32 -BOOL backup(const char*); -BOOL listfiles(const char*); -#if POSIXACLS -BOOL iterate(RECURSE, const char*, const struct POSIX_SECURITY*); -#else -BOOL iterate(RECURSE, const char*, mode_t); -#endif -#else -BOOL backup(const char*, const char*); -BOOL listfiles(const char*, const char*); -BOOL mapproposal(const char*, const char*); -#endif -#if POSIXACLS -BOOL setfull_posix(const char *, const struct POSIX_SECURITY*, BOOL); -struct POSIX_SECURITY *linux_permissions_posix(const char*, BOOL); -BOOL recurseset_posix(const char*, const struct POSIX_SECURITY*); -BOOL singleset_posix(const char*, const struct POSIX_SECURITY*); -struct POSIX_SECURITY *encode_posix_acl(const char*); -#endif -static void *stdmalloc(size_t); -static void stdfree(void*); +#define ROOT_OWNER_UNMARK SYNCHRONIZE /* ACL granted to root as owner */ +#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */ -BOOL valid_sds(const char*, unsigned int, unsigned int, - unsigned int, u32, BOOL); -BOOL valid_sii(const char*, u32); -BOOL valid_sdh(const char*, u32, u32); -int consist_sds(const char*, unsigned int, unsigned int, BOOL); -int consist_sii(const char*); -int consist_sdh(const char*); -int audit_sds(BOOL); -int audit_sii(void); -int audit_sdh(void); -void audit_summary(void); -BOOL audit(const char*); -int getoptions(int, char*[]); +#define INSDS1 1 +#define INSDS2 2 +#define INSII 4 +#define INSDH 8 -#ifndef WIN32 +struct SII { /* this is an image of an $SII index entry */ + le16 offs; + le16 size; + le32 fill1; + le16 indexsz; + le16 indexksz; + le16 flags; + le16 fill2; + le32 keysecurid; + + /* did not find official description for the following */ + le32 hash; + le32 securid; + le32 dataoffsl; /* documented as badly aligned */ + le32 dataoffsh; + le32 datasize; +} ; + +struct SDH { /* this is an image of an $SDH index entry */ + le16 offs; + le16 size; + le32 fill1; + le16 indexsz; + le16 indexksz; + le16 flags; + le16 fill2; + le32 keyhash; + le32 keysecurid; + + /* did not find official description for the following */ + le32 hash; + le32 securid; + le32 dataoffsl; + le32 dataoffsh; + le32 datasize; + le32 fill3; + } ; + +#ifdef HAVE_WINDOWS_H +/* + * Including leads to numerous conflicts with layout.h + * so define a few needed Windows calls unrelated to ntfs-3g + */ +BOOL WINAPI LookupAccountSidA(const char*, void*, char*, u32*, + char*, u32*, s32*); +u32 WINAPI GetFileAttributesA(const char*); +#endif /* HAVE_WINDOWS_H */ + +#define INVALID_FILE_ATTRIBUTES (-1)/* error from ntfs_get_file_attributes() */ /* - * Structures for collecting directory contents (Linux only) + * Structures for collecting directory contents */ struct LINK { @@ -562,18 +459,27 @@ struct CALLBACK { const char *dir; } ; -int callback(struct CALLBACK *context, char *ntfsname, - int length, int type, long long pos, u64 mft_ref, - unsigned int dt_type); -#endif +static int callback(void *context, const ntfschar *ntfsname, + const int length, const int type, const s64 pos, + const MFT_REF mft_ref, const unsigned int dt_type); + +struct SECURITY_DATA { + u64 offset; + char *attr; + u32 hash; + u32 length; + unsigned int filecount:16; + unsigned int mode:12; + unsigned int flags:4; +} ; /* * Global constants */ -#define BANNER "secaudit " AUDT_VERSION " : NTFS security data auditing" +#define BANNER "ntfssecaudit " AUDT_VERSION " : NTFS security data auditing" -#if SELFTESTS & !USESTUBS +#ifdef SELFTESTS /* * Dummy mapping file (self tests only) @@ -591,44 +497,18 @@ char dummymapping[] = "500::" DUMMYAUTH "1000\n" "::" DUMMYAUTH "10000\n"; /* - * SID for world (S-1-1-0) - */ - -static const char worldsidbytes[] = { - 1, /* revision */ - 1, /* auth count */ - 0, 0, 0, 0, 0, 1, /* base */ - 0, 0, 0, 0 /* 1st level */ -} ; -static const SID *worldsid = (const SID*)worldsidbytes; - -/* * SID for authenticated user (S-1-5-11) */ - + static const char authsidbytes[] = { - 1, /* revision */ + 1, /* revision */ 1, /* auth count */ 0, 0, 0, 0, 0, 5, /* base */ 11, 0, 0, 0 /* 1st level */ }; - + static const SID *authsid = (const SID*)authsidbytes; -/* - * SID for administrator (S-1-5-32-544) - */ - -static const char adminsidbytes[] = { - 1, /* revision */ - 2, /* auth count */ - 0, 0, 0, 0, 0, 5, /* base */ - 32, 0, 0, 0, /* 1st level */ - 32, 2, 0, 0 /* 2nd level */ -}; - -static const SID *adminsid = (const SID*)adminsidbytes; - /* * SID for local users (S-1-5-32-545) */ @@ -643,180 +523,101 @@ static const char localsidbytes[] = { static const SID *localsid = (const SID*)localsidbytes; -/* +/* * SID for system (S-1-5-18) */ - + static const char systemsidbytes[] = { - 1, /* revision */ + 1, /* revision */ 1, /* auth count */ 0, 0, 0, 0, 0, 5, /* base */ 18, 0, 0, 0 /* 1st level */ }; - + static const SID *systemsid = (const SID*)systemsidbytes; -#endif +#endif /* SELFTESTS */ /* * Global variables */ -BOOL opt_a; /* audit security data */ -BOOL opt_b; /* backup NTFS ACLs */ BOOL opt_e; /* restore extra (currently windows attribs) */ -BOOL opt_h; /* display an hexadecimal descriptor in a file */ BOOL opt_r; /* recursively apply to subdirectories */ -BOOL opt_s; /* restore NTFS ACLs */ BOOL opt_u; /* user mapping proposal */ -#if SELFTESTS & !USESTUBS -BOOL opt_t; /* run self-tests */ -#endif int opt_v; /* verbose or very verbose*/ +CMDS cmd; /* command to process */ struct SECURITY_DATA *securdata[(MAXSECURID + (1 << SECBLKSZ) - 1)/(1 << SECBLKSZ)]; -#if FORCEMASK -BOOL opt_m; /* force a mask - dangerous */ -u32 forcemsk /* mask to force */ -#endif unsigned int errors; /* number of severe errors */ unsigned int warnings; /* number of non-severe errors */ -struct CHKALLOC *firstalloc; struct SECURITY_CONTEXT context; MAPTYPE mappingtype; - -#ifdef STSC -#define static -#endif - -#ifndef WIN32 - -void *ntfs_handle; -void *ntfs_context = (void*)NULL; +struct SECURITY_API *ntfs_context = (struct SECURITY_API*)NULL; /* - * Open and close the security API (platform dependent) + * Open and close the security API (obsolete) */ -BOOL open_security_api(void) +static BOOL open_security_api(void) { -#if USESTUBS | defined(STSC) return (TRUE); -#else - char *error; - BOOL err; - const char *libfile; - - err = TRUE; - libfile = getenv(ENVNTFS3G); - if (!libfile) - libfile = (sizeof(char*) == 8 ? LIBFILE64 : LIBFILE); -#ifdef __SVR4 - /* do not override library functions by caller ones */ - ntfs_handle = dlopen(libfile,RTLD_LAZY | RTLD_GROUP); -#else - ntfs_handle = dlopen(libfile,RTLD_LAZY); -#endif - if (ntfs_handle) { - ntfs_initialize_file_security = (type_initialize_file_security) - dlsym(ntfs_handle,INIT_FILE_SECURITY); - error = dlerror(); - if (error) - fprintf(stderr," %s\n",error); - else { - ntfs_leave_file_security = (type_leave_file_security) - dlsym(ntfs_handle,LEAVE_FILE_SECURITY); - ntfs_get_file_security = (type_get_file_security) - dlsym(ntfs_handle,GET_FILE_SECURITY); - ntfs_set_file_security = (type_set_file_security) - dlsym(ntfs_handle,SET_FILE_SECURITY); - ntfs_get_file_attributes = (type_get_file_attributes) - dlsym(ntfs_handle,GET_FILE_ATTRIBUTES); - ntfs_set_file_attributes = (type_set_file_attributes) - dlsym(ntfs_handle,SET_FILE_ATTRIBUTES); - ntfs_read_directory = (type_read_directory) - dlsym(ntfs_handle,READ_DIRECTORY); - ntfs_read_sds = (type_read_sds) - dlsym(ntfs_handle,READ_SDS); - ntfs_read_sii = (type_read_sii) - dlsym(ntfs_handle,READ_SII); - ntfs_read_sdh = (type_read_sdh) - dlsym(ntfs_handle,READ_SDH); - ntfs_get_user = (type_get_user) - dlsym(ntfs_handle,GET_USER); - ntfs_get_group = (type_get_group) - dlsym(ntfs_handle,GET_GROUP); - ntfs_get_usid = (type_get_usid) - dlsym(ntfs_handle,GET_USID); - ntfs_get_gsid = (type_get_gsid) - dlsym(ntfs_handle,GET_GSID); - err = !ntfs_initialize_file_security - || !ntfs_leave_file_security - || !ntfs_get_file_security - || !ntfs_set_file_security - || !ntfs_get_file_attributes - || !ntfs_set_file_attributes - || !ntfs_read_directory - || !ntfs_read_sds - || !ntfs_read_sii - || !ntfs_read_sdh - || !ntfs_get_user - || !ntfs_get_group - || !ntfs_get_usid - || !ntfs_get_gsid; - - if (error) - fprintf(stderr,"ntfs-3g API not available\n"); - } - } else { - fprintf(stderr,"Could not open ntfs-3g library\n"); - fprintf(stderr,"\nPlease set environment variable \"" ENVNTFS3G "\"\n"); - fprintf(stderr,"to appropriate path and retry\n"); - } - return (!err); -#endif /* USESTUBS | defined(STSC) */ } -BOOL close_security_api(void) +static BOOL close_security_api(void) { -#if USESTUBS | defined(STSC) return (0); -#else - return (!dlclose(ntfs_handle)); -#endif /* USESTUBS | defined(STSC) */ } /* - * Open and close a volume (platform dependent) + * Open and close a volume * Assumes a single volume is opened */ -BOOL open_volume(const char *volume, unsigned long flags) +static BOOL open_volume(const char *volume, unsigned long flags) { BOOL ok; ok = FALSE; if (!ntfs_context) { - ntfs_context = ntfs_initialize_file_security(volume,flags); + ntfs_context = ntfs_initialize_file_security(volume, flags); if (ntfs_context) { if (*(u32*)ntfs_context != MAGIC_API) { fprintf(stderr,"Versions of ntfs-3g and secaudit" " are not compatible\n"); } else { - fprintf(stderr,"\"%s\" opened\n",volume); + fprintf(stderr,"\"%s\" opened %s\n",volume, + (flags & NTFS_MNT_RDONLY + ? "read-only" : "read-write")); mappingtype = MAPEXTERN; ok = TRUE; } } else { fprintf(stderr,"Could not open \"%s\"\n",volume); +#ifdef HAVE_WINDOWS_H + switch (errno) { + case EACCES : + fprintf(stderr,"You need Administrator rights to open \"%s\"\n", + volume); + break; + case EBUSY : + fprintf(stderr,"Looks like \"%s\" is mounted,\n",volume); + fprintf(stderr,"close all applications using it\n"); + break; + default : + fprintf(stderr,"Close all applications using %s\n", volume); + fprintf(stderr,"to make sure it is not mounted\n"); + } +#else fprintf(stderr,"Make sure \"%s\" is not mounted\n",volume); +#endif } } else fprintf(stderr,"A volume is already open\n"); return (ok); } -BOOL close_volume(const char *volume) +static BOOL close_volume(const char *volume) { BOOL r; @@ -825,17 +626,84 @@ BOOL close_volume(const char *volume) fprintf(stderr,"\"%s\" closed\n",volume); else fprintf(stderr,"Could not close \"%s\"\n",volume); - ntfs_context = (void*)NULL; + ntfs_context = (struct SECURITY_API*)NULL; return (r); } -#endif /* WIN32 */ +#ifdef HAVE_WINDOWS_H + +/* + * Make a path suitable for feeding to libntfs-3g + * + * Use '/' as a directory separator and remove /../ and /./ + */ + +static int cleanpath(char *path) +{ + int err; + char *p; + char *s, *d; + + err = 0; + for (p=path; *p; p++) + if (*p == '\\') + *p = '/'; + do { + s = (char*)NULL; + p = strstr(path, "/./"); + if (p) { + s = p + 3; + d = p + 1; + } else { + p = strstr(path, "/../"); + if (p) { + d = p; + while ((d != path) && (*--d != '/')) + d--; + if ((d != p) && (*d == '/')) { + s = p + 3; + } else + err = 1; + } + } + if (s) { + while (*s) + *d++ = *s++; + *d = 0; + } + } while (s && !err); + return (err); +} + +/* + * Build a path with Unix-type separators + * + * The path from the ntfs root is required for libntfs-3g calls + */ + +static char *unixname(const char *name) +{ + char *uname; + + uname = (char*)malloc(strlen(name) + 1); + if (uname) { + strcpy(uname, name); + if (cleanpath(uname)) { + fprintf(stderr,"Bad path %s\n",name); + free(uname); + uname = (char*)NULL; + } + } + return (uname); +} + +#endif /* HAVE_WINDOWS_H */ /* * Extract small or big endian data from an array of bytes */ -unsigned int get2l(const char *attr, int p) +static unsigned int get2l(const char *attr, int p) { int i; unsigned int v; @@ -846,7 +714,7 @@ unsigned int get2l(const char *attr, int p) return (v); } -unsigned long get4l(const char *attr, int p) +static unsigned long get4l(const char *attr, int p) { int i; unsigned long v; @@ -857,18 +725,7 @@ unsigned long get4l(const char *attr, int p) return (v); } -u64 get6l(const char *attr, int p) -{ - int i; - u64 v; - - v = 0; - for (i=0; i<6; i++) - v += ((long long)(attr[p+i] & 255)) << (8*i); - return (v); -} - -u64 get6h(const char *attr, int p) +static u64 get6h(const char *attr, int p) { int i; u64 v; @@ -879,7 +736,7 @@ u64 get6h(const char *attr, int p) return (v); } -u64 get8l(const char *attr, int p) +static u64 get8l(const char *attr, int p) { int i; u64 v; @@ -894,7 +751,7 @@ u64 get8l(const char *attr, int p) * Set small or big endian data into an array of bytes */ -void set2l(char *p, unsigned int v) +static void set2l(char *p, unsigned int v) { int i; @@ -902,7 +759,7 @@ void set2l(char *p, unsigned int v) p[i] = ((v >> 8*i) & 255); } -void set4l(char *p, unsigned long v) +static void set4l(char *p, unsigned long v) { int i; @@ -915,7 +772,7 @@ void set4l(char *p, unsigned long v) * hexadecimal dump of an array of bytes */ -void hexdump(const char *attr, int size, int level) +static void hexdump(const char *attr, int size, int level) { int i,j; @@ -929,7 +786,7 @@ void hexdump(const char *attr, int size, int level) } } -u32 hash(const le32 *buf, int size /* bytes */) +static u32 hash(const le32 *buf, int size /* bytes */) { u32 h; int i; @@ -946,50 +803,45 @@ u32 hash(const le32 *buf, int size /* bytes */) * Returns 0 for invalid input */ -unsigned int utf8size(const char *utf16, int length) +static unsigned int utf8size(const ntfschar *utf16, int length) { int i; - unsigned int size; - enum { BASE, SURR, ERR } state; + int count = 0; + BOOL surrog; + BOOL fail; - size = 0; - state = BASE; - for (i=0; i<2*length; i+=2) { - switch (state) { - case BASE : - if (utf16[i+1] & 0xf8) { - if ((utf16[i+1] & 0xf8) == 0xd8) - state = (utf16[i+1] & 4 ? ERR : SURR); - else + surrog = FALSE; + fail = FALSE; + for (i = 0; i < length && utf16[i] && !fail; i++) { + unsigned short c = le16_to_cpu(utf16[i]); + if (surrog) { + if ((c >= 0xdc00) && (c < 0xe000)) { + surrog = FALSE; + count += 4; + } else + fail = TRUE; + } else + if (c < 0x80) + count++; + else if (c < 0x800) + count += 2; + else if (c < 0xd800) + count += 3; + else if (c < 0xdc00) + surrog = TRUE; #if NOREVBOM - if (((utf16[i+1] & 0xff) == 0xff) - && ((utf16[i] & 0xfe) == 0xfe)) - state = ERR; - else - size += 3; + else if ((c >= 0xe000) && (c < 0xfffe)) #else - size += 3; + else if (c >= 0xe000) #endif - } else - if ((utf16[i] & 0x80) || utf16[i+1]) - size += 2; - else - size++; - break; - case SURR : - if ((utf16[i+1] & 0xfc) == 0xdc) { - state = BASE; - size += 4; - } else - state = ERR; - break; - case ERR : - break; - } + count += 3; + else + fail = TRUE; } - if (state != BASE) - size = 0; - return (size); + if (surrog) + fail = TRUE; + + return (fail ? 0 : count); } /* @@ -999,368 +851,57 @@ unsigned int utf8size(const char *utf16, int length) * Returns size or zero for invalid input */ -unsigned int makeutf8(char *utf8, const char *utf16, int length) +static unsigned int makeutf8(char *utf8, const ntfschar *utf16, int length) { - int i; - unsigned int size; - unsigned int rem; - enum { BASE, SURR, ERR } state; + int size; - size = 0; - rem = 0; - state = BASE; - for (i=0; i<2*length; i+=2) { - switch (state) { - case BASE : - if (utf16[i+1] & 0xf8) { - if ((utf16[i+1] & 0xf8) == 0xd8) { - if (utf16[i+1] & 4) - state = ERR; - else { - utf8[size++] = 0xf0 + (utf16[i+1] & 7) - + ((utf16[i] & 0xc0) == 0xc0); - utf8[size++] = 0x80 + (((utf16[i] + 64) >> 2) & 63); - rem = utf16[i] & 3; - state = SURR; - } - } else { -#if NOREVBOM - if (((utf16[i+1] & 0xff) == 0xff) - && ((utf16[i] & 0xfe) == 0xfe)) - state = ERR; - else { - utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15); - utf8[size++] = 0x80 - + ((utf16[i+1] & 15) << 2) - + ((utf16[i] >> 6) & 3); - utf8[size++] = 0x80 + (utf16[i] & 63); - } -#else - utf8[size++] = 0xe0 + ((utf16[i+1] >> 4) & 15); - utf8[size++] = 0x80 - + ((utf16[i+1] & 15) << 2) - + ((utf16[i] >> 6) & 3); - utf8[size++] = 0x80 + (utf16[i] & 63); -#endif - } - } else - if ((utf16[i] & 0x80) || utf16[i+1]) { - utf8[size++] = 0xc0 - + ((utf16[i+1] & 15) << 2) - + ((utf16[i] >> 6) & 3); - utf8[size++] = 0x80 + (utf16[i] & 63); - } else - utf8[size++] = utf16[i]; - break; - case SURR : - if ((utf16[i+1] & 0xfc) == 0xdc) { - utf8[size++] = 0x80 + (rem << 4) - + ((utf16[i+1] & 3) << 2) - + ((utf16[i] >> 6) & 3); - utf8[size++] = 0x80 + (utf16[i] & 63); - state = BASE; - } else - state = ERR; - break; - case ERR : - break; - } - } - utf8[size] = 0; - if (state != BASE) - state = ERR; - return (state == ERR ? 0 : size); + size = ntfs_ucstombs(utf16, length, &utf8, MAXFILENAME); + return (size < 0 ? 0 : size); } -#ifdef WIN32 - -/* - * Evaluate the size of UTF-16LE conversion of a UTF-8 text - * (basic conversions only) - * trailing '\0' not accounted for - */ - -unsigned int utf16size(const char *utf8) -{ - unsigned int size; - const char *p; - int c; - unsigned int code; - enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, ERR } state; - - p = utf8; - size = 0; - state = BASE; - while (*p) { - c = *p++ & 255; - switch (state) { - case BASE : - if (!(c & 0x80)) - size++; - else - if (c < 0xc2) - state = ERR; - else - if (c < 0xe0) - state = TWO; - else - if (c < 0xf0) { - if (c == 0xe0) - state = THREE2; - else - if (c == 0xed) - state = THREE3; - else - state = THREE; - } else - if (c < 0xf8) { - state = FOUR; - code = c & 7; - } else - state = ERR; - break; - case TWO : - if ((c & 0xc0) != 0x80) - state = ERR; - else { - size++; - state = BASE; - } - break; - case THREE : - if ((c & 0xc0) != 0x80) - state = ERR; - else - state = TWO; - break; - case THREE2 : - if ((c & 0xe0) != 0xa0) - state = ERR; - else - state = TWO; - break; - case THREE3 : - if ((c & 0xe0) != 0x80) - state = ERR; - else - state = TWO; - break; - case FOUR : - if ((((code << 6) + (c & 63)) > 0x10f) - || (((code << 6) + (c & 63)) < 0x10)) - state = ERR; - else { - size++; - state = THREE; - } - break; - case ERR : - break; - } - } - if (state != BASE) size = 0; - return (size); -} - -/* - * Convert a UTF8 text to UTF-16LE - * (basic conversions only) - * Note : mbstowcs() not used because on Linux it fails for characters - * not present in current locale - */ - -unsigned int makeutf16(char *target, const char *utf8) -{ - unsigned int size; - unsigned int code; - const char *p; - int c; - enum { BASE, TWO, THREE, THREE2, THREE3, FOUR, FOUR2, FOUR3, ERR } state; - - p = utf8; - size = 0; - c = 0; - state = BASE; - while (*p) { - c = *p++ & 255; - switch (state) { - case BASE : - if (!(c & 0x80)) { - target[2*size] = c; - target[2*size + 1] = 0; - size++; - } else { - if (c < 0xc2) - state = ERR; - else - if (c < 0xe0) { - code = c & 31; - state = TWO; - } else - if (c < 0xf0) { - code = c & 15; - if (c == 0xe0) - state = THREE2; - else - if (c == 0xed) - state = THREE3; - else - state = THREE; - } else - if (c < 0xf8) { - code = c & 7; - state = FOUR; - } else - state = ERR; - } - break; - case TWO : -#if NOREVBOM - if (((c & 0xc0) != 0x80) - || ((code == 0x3ff) && (c >= 0xbe))) -#else - if ((c & 0xc0) != 0x80) -#endif - state = ERR; - else { - target[2*size] = ((code & 3) << 6) + (c & 63); - target[2*size + 1] = ((code >> 2) & 255); - size++; - state = BASE; - } - break; - case THREE : - if ((c & 0xc0) != 0x80) - state = ERR; - else { - code = ((code & 15) << 6) + (c & 63); - state = TWO; - } - break; - case THREE2 : - if ((c & 0xe0) != 0xa0) - state = ERR; - else { - code = ((code & 15) << 6) + (c & 63); - state = TWO; - } - break; - case THREE3 : - if ((c & 0xe0) != 0x80) - state = ERR; - else { - code = ((code & 15) << 6) + (c & 63); - state = TWO; - } - break; - case FOUR : - if ((c & 0xc0) != 0x80) - state = ERR; - else { - code = (code << 6) + (c & 63); - state = FOUR2; - } - break; - case FOUR2 : - if ((c & 0xc0) != 0x80) - state = ERR; - else { - code = (code << 6) + (c & 63); - state = FOUR3; - } - break; - case FOUR3 : - if ((code > 0x43ff) - || (code < 0x400) - || ((c & 0xc0) != 0x80)) - state = ERR; - else { - target[2*size] = ((code - 0x400) >> 4) & 255; - target[2*size+1] = 0xd8 + (((code - 0x400) >> 12) & 3); - target[2*size+2] = ((code & 3) << 6) + (c & 63); - target[2*size+3] = 0xdc + ((code >> 2) & 3); - size += 2; - state = BASE; - } - break; - case ERR : - break; - } - } - if (state != BASE) - size = 0; - target[2*size] = 0; - target[2*size + 1] = 0; - return (size); -} - -unsigned int utf16len(const char *str) -{ - unsigned int len; - - len = 0; - while (str[2*len] || str[2*len+1]) len++; - return (len); -} - -#endif - /* * Print a file name * on Windows it prints UTF-16LE names as UTF-8 */ -void printname(FILE *file, const char *name) +static void printname(FILE *file, const char *name) { -#ifdef WIN32 - char utf8name[MAXFILENAME]; +#ifdef HAVE_WINDOWS_H + char *wname; + char *p; - makeutf8(utf8name,name,utf16len(name)); - fprintf(file,"%s",utf8name); -#else + wname = (char*)malloc(strlen(name) + 1); + if (wname) { + strcpy(wname, name); + for (p=wname; *p; p++) + if (*p == '/') + *p = '\\'; + fprintf(file,"%s", wname); + free(wname); + } +#else /* HAVE_WINDOWS_H */ fprintf(file,"%s",name); -#endif +#endif /* HAVE_WINDOWS_H */ } /* * Print the last error code */ -void printerror(FILE *file) +static void printerror(FILE *file) { -#ifdef WIN32 - int err; - const char *txt; - - err = GetLastError(); - switch (err) { - case 5 : - txt = "Access to security descriptor was denied"; + if (errno) + fprintf(file,"Error code %d : %s\n",errno,strerror(errno)); + switch (errno) { + case EACCES : + fprintf(file,"You probably need Administrator rights\n"); break; - case 1307 : - txt = "This SID may not be assigned as the owner of this object"; - break; - case 1308 : - txt = "This SID may not be assigned as the group of this object"; - break; - case 1314 : - txt = "You do not have the privilege to change this SID"; + case EBUSY : + fprintf(file,"You probably try to write to a mounted device\n"); break; default : - txt = (const char*)NULL; break; } - if (txt) - fprintf(file,"Error %d : %s\n",err,txt); - else - fprintf(file,"Error %d\n",err); -#else -#ifdef STSC - if (errno) fprintf(file,"Error code %d\n",errno); -#else - if (errno) fprintf(file,"Error code %d : %s\n",errno,strerror(errno)); -#endif -#endif } #ifndef HAVE_SYSLOG_H @@ -1369,7 +910,7 @@ void printerror(FILE *file) * Redefine early error messages in stand-alone situations */ -void ntfs_log_early_error(const char *format, ...) +static void ntfs_log_early_error(const char *format, ...) { va_list args; @@ -1378,7 +919,7 @@ void ntfs_log_early_error(const char *format, ...) va_end(args); } -#endif +#endif /* HAVE_SYSLOG_H */ /* * Guess whether a security attribute is intended for a directory @@ -1386,7 +927,7 @@ void ntfs_log_early_error(const char *format, ...) * (not 100% reliable) */ -BOOL guess_dir(const char *attr) +static BOOL guess_dir(const char *attr) { int off; int isdir; @@ -1413,7 +954,7 @@ BOOL guess_dir(const char *attr) * See http://msdn2.microsoft.com/en-us/library/aa379649.aspx */ -void showsid(const char *attr, int off, const char *prefix, int level) +static void showsid(const char *attr, int off, const char *prefix, int level) { int cnt; int i; @@ -1424,7 +965,7 @@ void showsid(const char *attr, int off, const char *prefix, int level) unsigned long last; char marker; - if (opt_b) + if (cmd == CMD_BACKUP) marker = '#'; else marker = ' '; @@ -1566,23 +1107,23 @@ void showsid(const char *attr, int off, const char *prefix, int level) if (!known) printf("%*cUnknown SID\n",-level,marker); printf("%*c%shex S-%d-",-level,marker,prefix,attr[off] & 255); - printf("%llx",auth); + printf("%llx",(long long)auth); for (i=0; iowner)]; usid = ntfs_acl_owner((const char*)attr); -#if SELFTESTS & !USESTUBS - if (!opt_t && !ntfs_same_sid(usid,osid)) - printf("== Linux owner is different from Windows owner\n"); -#else +#ifdef SELFTESTS + if ((cmd != CMD_TEST) && !ntfs_same_sid(usid,osid)) + printf("== Linux owner is different from Windows owner\n"); +#else /* SELFTESTS */ if (!ntfs_same_sid(usid,osid)) - printf("== Linux owner is different from Windows owner\n"); -#endif -#else + printf("== Linux owner is different from Windows owner\n"); +#endif /* SELFTESTS */ +#else /* OWNERFROMACL */ usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; -#endif - posix_desc = ntfs_build_permissions_posix(context.mapping, - (const char*)attr, usid, gsid, isdir); +#endif /* OWNERFROMACL */ + if (mappingtype == MAPEXTERN) + posix_desc = ntfs_build_permissions_posix( + ntfs_context->security.mapping, + (const char*)attr, usid, gsid, isdir); + else + posix_desc = ntfs_build_permissions_posix(context.mapping, + (const char*)attr, usid, gsid, isdir); if (!posix_desc) { printf("** Failed to build a Posix descriptor\n"); errors++; @@ -2161,12 +1657,12 @@ struct POSIX_SECURITY *linux_permissions_posix(const char *attr, BOOL isdir) #endif /* POSIXACLS */ -int linux_permissions(const char *attr, BOOL isdir) +static int linux_permissions(const char *attr, BOOL isdir) { const SECURITY_DESCRIPTOR_RELATIVE *phead; #if OWNERFROMACL const SID *osid; -#endif +#endif /* OWNERFROMACL */ const SID *usid; const SID *gsid; int perm; @@ -2176,16 +1672,16 @@ int linux_permissions(const char *attr, BOOL isdir) #if OWNERFROMACL osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; usid = ntfs_acl_owner((const char*)attr); -#if SELFTESTS & !USESTUBS - if (!opt_t && !ntfs_same_sid(usid,osid)) - printf("== Linux owner is different from Windows owner\n"); -#else +#ifdef SELFTESTS + if ((cmd != CMD_TEST) && !ntfs_same_sid(usid,osid)) + printf("== Linux owner is different from Windows owner\n"); +#else /* SELFTESTS */ if (!ntfs_same_sid(usid,osid)) - printf("== Linux owner is different from Windows owner\n"); -#endif -#else + printf("== Linux owner is different from Windows owner\n"); +#endif /* SELFTESTS */ +#else /* OWNERFROMACL */ usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; -#endif +#endif /* OWNERFROMACL */ perm = ntfs_build_permissions((const char*)attr, usid, gsid, isdir); if (perm < 0) { printf("** Failed to build permissions\n"); @@ -2194,31 +1690,31 @@ int linux_permissions(const char *attr, BOOL isdir) return (perm); } -uid_t linux_owner(const char *attr) +static uid_t linux_owner(const char *attr) { const SID *usid; uid_t uid; #if OWNERFROMACL usid = ntfs_acl_owner((const char*)attr); -#else +#else /* OWNERFROMACL */ const SECURITY_DESCRIPTOR_RELATIVE *phead; phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; -#endif -#if defined(WIN32) | defined(STSC) +#endif /* OWNERFROMACL */ +#ifdef HAVE_WINDOWS_H uid = ntfs_find_user(context.mapping[MAPUSERS],usid); -#else +#else /* defined(HAVE_WINDOWS_H) */ if (mappingtype == MAPEXTERN) uid = relay_find_user(context.mapping[MAPUSERS],usid); else uid = ntfs_find_user(context.mapping[MAPUSERS],usid); -#endif +#endif /* defined(HAVE_WINDOWS_H) */ return (uid); } -gid_t linux_group(const char *attr) +static gid_t linux_group(const char *attr) { const SECURITY_DESCRIPTOR_RELATIVE *phead; const SID *gsid; @@ -2226,18 +1722,18 @@ gid_t linux_group(const char *attr) phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; gsid = (const SID*)&attr[le32_to_cpu(phead->group)]; -#if defined(WIN32) | defined(STSC) +#ifdef HAVE_WINDOWS_H gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid); -#else +#else /* defined(HAVE_WINDOWS_H) */ if (mappingtype == MAPEXTERN) gid = relay_find_group(context.mapping[MAPGROUPS],gsid); else gid = ntfs_find_group(context.mapping[MAPGROUPS],gsid); -#endif +#endif /* defined(HAVE_WINDOWS_H) */ return (gid); } -void newblock(s32 key) +static void newblock(s32 key) { struct SECURITY_DATA *psecurdata; int i; @@ -2256,7 +1752,7 @@ void newblock(s32 key) } } -void freeblocks(void) +static void freeblocks(void) { int i,j; struct SECURITY_DATA *psecurdata; @@ -2276,19 +1772,19 @@ void freeblocks(void) * Basic read from a user mapping file (Win32) */ -int basicread(void *fileid, char *buf, size_t size, +static int basicread(void *fileid, char *buf, size_t size, off_t pos __attribute__((unused))) { return (read(*(int*)fileid, buf, size)); } -#if SELFTESTS & !USESTUBS +#ifdef SELFTESTS /* * Read a dummy mapping file for tests */ -int dummyread(void *fileid __attribute__((unused)), +static int dummyread(void *fileid __attribute__((unused)), char *buf, size_t size, off_t pos) { size_t sz; @@ -2305,7 +1801,7 @@ int dummyread(void *fileid __attribute__((unused)), return (sz); } -#endif /* POSIXACLS & SELFTESTS & !USESTUBS */ +#endif /* SELFTESTS */ /* * Apply default single user mapping @@ -2323,24 +1819,12 @@ static int do_default_mapping(struct MAPPING *mapping[], res = -1; sidsz = ntfs_sid_size(usid); -#if USESTUBS - sid = (SID*)stdmalloc(sidsz); /* will be freed within the library */ -#else sid = (SID*)ntfs_malloc(sidsz); -#endif if (sid) { memcpy(sid,usid,sidsz); -#if USESTUBS - usermapping = (struct MAPPING*)stdmalloc(sizeof(struct MAPPING)); -#else usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING)); -#endif if (usermapping) { -#if USESTUBS - groupmapping = (struct MAPPING*)stdmalloc(sizeof(struct MAPPING)); -#else groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING)); -#endif if (groupmapping) { usermapping->sid = sid; usermapping->xid = 0; @@ -2369,15 +1853,15 @@ static int do_default_mapping(struct MAPPING *mapping[], * (failure should not be interpreted as an error) */ -int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) +static int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) { -#ifdef WIN32 +#ifdef HAVE_WINDOWS_H char mapfile[sizeof(MAPDIR) + sizeof(MAPFILE) + 6]; - char currpath[261]; -#else + char currpath[MAXFILENAME]; +#else /* HAVE_WINDOWS_H */ char *mapfile; char *p; -#endif +#endif /* HAVE_WINDOWS_H */ int fd; struct MAPLIST *item; struct MAPLIST *firstitem = (struct MAPLIST*)NULL; @@ -2405,28 +1889,32 @@ int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) mapping[MAPGROUPS] = (struct MAPPING*)NULL; if (usermap_path) { -#ifdef WIN32 +#ifdef HAVE_WINDOWS_H /* TODO : check whether the device can store acls */ strcpy(mapfile,"x:\\" MAPDIR "\\" MAPFILE); if (((const le16*)usermap_path)[1] == ':') mapfile[0] = usermap_path[0]; else { - GetModuleFileName(NULL, currpath, 261); + getcwd(currpath,MAXFILENAME); mapfile[0] = currpath[0]; } fd = open(mapfile,O_RDONLY); -#else +#else /* HAVE_WINDOWS_H */ fd = 0; mapfile = (char*)malloc(MAXFILENAME); if (mapfile) { /* build a full path to locate the mapping file */ +/* if ((usermap_path[0] != '/') && getcwd(mapfile,MAXFILENAME)) { strcat(mapfile,"/"); strcat(mapfile,usermap_path); } else strcpy(mapfile,usermap_path); - p = strrchr(mapfile,'/'); +*/ + p = ntfs_realpath(usermap_path, mapfile); + if (p) + p = strrchr(mapfile,'/'); if (p) do { strcpy(p,"/" MAPDIR "/" MAPFILE); @@ -2446,15 +1934,15 @@ int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) errors++; } } -#endif +#endif /* HAVE_WINDOWS_H */ if (fd > 0) { firstitem = ntfs_read_mapping(basicread, (void*)&fd); close(fd); } } else { -#if SELFTESTS & !USESTUBS +#ifdef SELFTESTS firstitem = ntfs_read_mapping(dummyread, (void*)NULL); -#endif +#endif /* SELFTESTS */ } if (firstitem) { @@ -2469,11 +1957,7 @@ int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) /* and rely on internal representation */ while (firstitem) { item = firstitem->next; -#if USESTUBS - stdfree(firstitem); /* allocated within library */ -#else free(firstitem); -#endif firstitem = item; } } else { @@ -2488,7 +1972,7 @@ int local_build_mapping(struct MAPPING *mapping[], const char *usermap_path) * Get an hexadecimal number (source with MSB first) */ -u32 getmsbhex(const char *text) +static u32 getmsbhex(const char *text) { u32 v; int b; @@ -2517,7 +2001,7 @@ u32 getmsbhex(const char *text) * An odd number of digits might yield a strange result */ -u32 getlsbhex(const char *text) +static u32 getlsbhex(const char *text) { u32 v; int b; @@ -2548,7 +2032,7 @@ u32 getlsbhex(const char *text) * Check whether a line looks like an hex dump */ -BOOL ishexdump(const char *line, int first, int lth) +static BOOL ishexdump(const char *line, int first, int lth) { BOOL ok; int i; @@ -2578,13 +2062,13 @@ BOOL ishexdump(const char *line, int first, int lth) * This is typically to convert a verbose output to a very verbose one */ -void showhex(FILE *fd) +static void showhex(FILE *fd) { static char attr[MAXATTRSZ]; char line[MAXLINE+1]; #if POSIXACLS struct POSIX_SECURITY *pxdesc; -#endif +#endif /* POSIXACLS */ int lth; int first; unsigned int pos; @@ -2646,7 +2130,7 @@ void showhex(FILE *fd) free(pxdesc); } } -#endif +#endif /* POSIXACLS */ pos = 0; } if (isdump && !off) @@ -2677,7 +2161,7 @@ void showhex(FILE *fd) } while (!done); } -BOOL applyattr(const char *fullname, const char *attr, +static BOOL applyattr(const char *fullname, const char *attr, BOOL withattr, int attrib, s32 key) { struct SECURITY_DATA *psecurdata; @@ -2687,10 +2171,6 @@ BOOL applyattr(const char *fullname, const char *attr, BOOL bad; BOOL badattrib; BOOL err; -#ifdef WIN32 - HANDLE htoken; - TOKEN_PRIVILEGES tkp; -#endif err = FALSE; psecurdata = (struct SECURITY_DATA*)NULL; @@ -2708,11 +2188,7 @@ BOOL applyattr(const char *fullname, const char *attr, /* If we have a usable attrib value. Try applying */ badattrib = FALSE; if (opt_e && (attrib != INVALID_FILE_ATTRIBUTES)) { -#ifdef WIN32 - badattrib = !SetFileAttributesW((LPCWSTR)fullname, attrib); -#else badattrib = !ntfs_set_file_attributes(ntfs_context, fullname, attrib); -#endif if (badattrib) { printf("** Could not set Windows attrib of "); printname(stdout,fullname); @@ -2738,58 +2214,15 @@ BOOL applyattr(const char *fullname, const char *attr, */ if (psecurdata) curattr = psecurdata->attr; - + if (curattr) { -#ifdef WIN32 - selection = OWNER_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | DACL_SECURITY_INFORMATION; - if (OpenProcessToken(GetCurrentProcess(), - TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &htoken)) { - if (LookupPrivilegeValue(NULL, SE_SECURITY_NAME, - &tkp.Privileges[0].Luid)) { - tkp.PrivilegeCount = 1; - tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - if (AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0)) { - selection |= SACL_SECURITY_INFORMATION; - } - } - } - /* const missing from stupid prototype */ - bad = !SetFileSecurityW((LPCWSTR)fullname, - selection, (PSECURITY_DESCRIPTOR)(LONG_PTR)curattr); - if (bad) - switch (GetLastError()) { - case 1307 : - case 1314 : - printf("** Could not set owner or SACL of "); - printname(stdout,fullname); - printf(", retrying with no owner or SACL setting\n"); - warnings++; - /* const missing from stupid prototype */ - bad = !SetFileSecurityW((LPCWSTR)fullname, - selection & ~OWNER_SECURITY_INFORMATION - & ~SACL_SECURITY_INFORMATION, - (PSECURITY_DESCRIPTOR) - (LONG_PTR)curattr); - break; - default : - break; - } - /* Release privileges once we are done*/ - if (selection ^ SACL_SECURITY_INFORMATION) { - tkp.Privileges[0].Attributes = 0; - AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0); - } -#else selection = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION; bad = !ntfs_set_file_security(ntfs_context,fullname, selection, (const char*)curattr); -#endif if (bad) { printf("** Could not set the ACL of "); printname(stdout,fullname); @@ -2819,7 +2252,7 @@ BOOL applyattr(const char *fullname, const char *attr, * Restore security descriptors from a file */ -BOOL restore(FILE *fd) +static BOOL restore(FILE *fd) { static char attr[MAXATTRSZ]; char line[MAXFILENAME+25]; @@ -2962,17 +2395,13 @@ BOOL restore(FILE *fd) oldhash = 0; attrib = INVALID_FILE_ATTRIBUTES; if (!done) { -#ifdef WIN32 - if (!strncmp(line,"File ",5)) - makeutf16(fullname,&line[5]); - else - makeutf16(fullname,&line[10]); -#else if (!strncmp(line,"File ",5)) strcpy(fullname,&line[5]); else strcpy(fullname,&line[10]); -#endif +#ifdef HAVE_WINDOWS_H + cleanpath(fullname); +#endif /* HAVE_WINDOWS_H */ } } } while (!done); @@ -2980,13 +2409,7 @@ BOOL restore(FILE *fd) return (FALSE); } -/* - * Open the security API in rw mode for an ACL restoration - */ - -#ifdef WIN32 -#else -BOOL dorestore(const char *volume, FILE *fd) +static BOOL dorestore(const char *volume, FILE *fd) { BOOL err; @@ -3013,9 +2436,8 @@ BOOL dorestore(const char *volume, FILE *fd) } return (err); } -#endif /* WIN32 */ -#if POSIXACLS & SELFTESTS & !USESTUBS +#if POSIXACLS /* * Merge Posix ACL rights into an u32 (self test only) @@ -3025,7 +2447,7 @@ BOOL dorestore(const char *volume, FILE *fd) * * Only two users (U1, U2) and two groups (G1, G2) taken into account */ -u32 merge_rights(const struct POSIX_SECURITY *pxdesc, BOOL def) +static u32 merge_rights(const struct POSIX_SECURITY *pxdesc, BOOL def) { const struct POSIX_ACE *pxace; int i; @@ -3077,21 +2499,55 @@ u32 merge_rights(const struct POSIX_SECURITY *pxdesc, BOOL def) return (rights); } -void tryposix(struct POSIX_SECURITY *pxdesc) +static BOOL same_posix(struct POSIX_SECURITY *pxdesc1, + struct POSIX_SECURITY *pxdesc2) +{ + BOOL same; + int i; + + same = pxdesc1 + && pxdesc2 + && (pxdesc1->mode == pxdesc2->mode) + && (pxdesc1->acccnt == pxdesc2->acccnt) + && (pxdesc1->defcnt == pxdesc2->defcnt) + && (pxdesc1->firstdef == pxdesc2->firstdef) + && (pxdesc1->tagsset == pxdesc2->tagsset) + && (pxdesc1->acl.version == pxdesc2->acl.version) + && (pxdesc1->acl.flags == pxdesc2->acl.flags); + i = 0; + while (same && (i < pxdesc1->acccnt)) { + same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) + && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) + && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); + i++; + } + i = pxdesc1->firstdef; + while (same && (i < pxdesc1->firstdef + pxdesc1->defcnt)) { + same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) + && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) + && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); + i++; + } + return (same); +} + +#endif /* POSIXACLS */ + +#if POSIXACLS & SELFTESTS + +static void tryposix(struct POSIX_SECURITY *pxdesc) { le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), - const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), - const_cpu_to_le32(1016) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(DEFSECAUTH1), cpu_to_le32(DEFSECAUTH2), + cpu_to_le32(DEFSECAUTH3), cpu_to_le32(1016) } ; le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), - const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), - const_cpu_to_le32(513) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(DEFSECAUTH1), cpu_to_le32(DEFSECAUTH2), + cpu_to_le32(DEFSECAUTH3), cpu_to_le32(513) } ; char *attr; @@ -3137,41 +2593,9 @@ void tryposix(struct POSIX_SECURITY *pxdesc) } } -static BOOL same_posix(struct POSIX_SECURITY *pxdesc1, - struct POSIX_SECURITY *pxdesc2) -{ - BOOL same; - int i; +#endif /* POSIXACLS & SELFTESTS */ - same = pxdesc1 - && pxdesc2 - && (pxdesc1->mode == pxdesc2->mode) - && (pxdesc1->acccnt == pxdesc2->acccnt) - && (pxdesc1->defcnt == pxdesc2->defcnt) - && (pxdesc1->firstdef == pxdesc2->firstdef) - && (pxdesc1->tagsset == pxdesc2->tagsset) - && (pxdesc1->acl.version == pxdesc2->acl.version) - && (pxdesc1->acl.flags == pxdesc2->acl.flags); - i = 0; - while (same && (i < pxdesc1->acccnt)) { - same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) - && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) - && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); - i++; - } - i = pxdesc1->firstdef; - while (same && (i < pxdesc1->firstdef + pxdesc1->defcnt)) { - same = (pxdesc1->acl.ace[i].tag == pxdesc2->acl.ace[i].tag) - && (pxdesc1->acl.ace[i].perms == pxdesc2->acl.ace[i].perms) - && (pxdesc1->acl.ace[i].id == pxdesc2->acl.ace[i].id); - i++; - } - return (same); -} - -#endif /* POSIXACLS & SELFTESTS & !USESTUBS */ - -#if SELFTESTS & !USESTUBS +#ifdef SELFTESTS /* * Build a dummy security descriptor @@ -3180,7 +2604,7 @@ static BOOL same_posix(struct POSIX_SECURITY *pxdesc1, static char *build_dummy_descr(BOOL isdir __attribute__((unused)), const SID *usid, const SID *gsid, - int cnt, + int cnt, /* seq of int allow, SID *sid, int flags, u32 mask */ ...) { @@ -3239,9 +2663,9 @@ static char *build_dummy_descr(BOOL isdir __attribute__((unused)), pacl = (ACL*)&attr[pos]; pacl->revision = ACL_REVISION; pacl->alignment1 = 0; - pacl->size = const_cpu_to_le16(0); /* fixed later */ + pacl->size = cpu_to_le16(0); /* fixed later */ pacl->ace_count = cpu_to_le16(cnt); - pacl->alignment2 = const_cpu_to_le16(0); + pacl->alignment2 = cpu_to_le16(0); /* enter the ACEs */ @@ -3268,8 +2692,8 @@ static char *build_dummy_descr(BOOL isdir __attribute__((unused)), /* append usid and gsid if defined */ /* positions of ACL, USID and GSID into header */ - pnhead->owner = const_cpu_to_le32(0); - pnhead->group = const_cpu_to_le32(0); + pnhead->owner = cpu_to_le32(0); + pnhead->group = cpu_to_le32(0); if (usid) { memcpy(&attr[pos], usid, usidsz); pnhead->owner = cpu_to_le32(pos); @@ -3279,14 +2703,13 @@ static char *build_dummy_descr(BOOL isdir __attribute__((unused)), pnhead->group = cpu_to_le32(pos + usidsz); } /* positions of DACL and SACL into header */ - pnhead->sacl = const_cpu_to_le32(0); + pnhead->sacl = cpu_to_le32(0); if (cnt) { pacl->size = cpu_to_le16(aclsz); pnhead->dacl = - const_cpu_to_le32(sizeof( - SECURITY_DESCRIPTOR_RELATIVE)); + cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); } else - pnhead->dacl = const_cpu_to_le32(0); + pnhead->dacl = cpu_to_le32(0); if (!ntfs_valid_descr(attr,pos+usidsz+gsidsz)) { printf("** Bad sample descriptor\n"); free(attr); @@ -3302,7 +2725,7 @@ static char *build_dummy_descr(BOOL isdir __attribute__((unused)), * Check a few samples with special conditions */ -void check_samples() +static void check_samples(void) { char *descr = (char*)NULL; BOOL isdir = FALSE; @@ -3318,41 +2741,36 @@ void check_samples() struct POSIX_SECURITY *pxdesc; struct POSIX_SECURITY *pxsample; const char *txsample; -#endif +#endif /* POSIXACLS */ le32 owner1[] = /* S-1-5-21-1833069642-4243175381-1340018762-1003 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(1833069642), - const_cpu_to_le32(4243175381), const_cpu_to_le32(1340018762), - const_cpu_to_le32(1003) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(1833069642), cpu_to_le32(4243175381U), + cpu_to_le32(1340018762), cpu_to_le32(1003) } ; le32 group1[] = /* S-1-5-21-1833069642-4243175381-1340018762-513 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(1833069642), - const_cpu_to_le32(4243175381), const_cpu_to_le32(1340018762), - const_cpu_to_le32(513) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(1833069642), cpu_to_le32(4243175381U), + cpu_to_le32(1340018762), cpu_to_le32(513) } ; le32 group2[] = /* S-1-5-21-1607551490-981732888-1819828000-513 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(1607551490), - const_cpu_to_le32(981732888), const_cpu_to_le32(1819828000), - const_cpu_to_le32(513) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(1607551490), cpu_to_le32(981732888), + cpu_to_le32(1819828000), cpu_to_le32(513) } ; le32 owner3[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), - const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), - const_cpu_to_le32(1016) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(DEFSECAUTH1), cpu_to_le32(DEFSECAUTH2), + cpu_to_le32(DEFSECAUTH3), cpu_to_le32(1016) } ; le32 group3[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), - const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), - const_cpu_to_le32(513) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(DEFSECAUTH1), cpu_to_le32(DEFSECAUTH2), + cpu_to_le32(DEFSECAUTH3), cpu_to_le32(513) } ; #if POSIXACLS @@ -3361,7 +2779,7 @@ void check_samples() struct POSIX_ACE ace[4]; } sampletry1 = { - { 0645, 4, 0, 4, 0x35, + { 0645, 4, 0, 4, 0x35, 0, { POSIX_VERSION, 0, 0 } }, { @@ -3377,7 +2795,7 @@ void check_samples() struct POSIX_ACE ace[6]; } sampletry3 = { - { 0100, 6, 0, 6, 0x3f, + { 0100, 6, 0, 6, 0x3f, 0, { POSIX_VERSION, 0, 0 } }, { @@ -3395,7 +2813,7 @@ void check_samples() struct POSIX_ACE ace[8]; } sampletry4 = { - { 0140, 8, 0, 8, 0x3f, + { 0140, 8, 0, 8, 0x3f, 0, { POSIX_VERSION, 0, 0 } }, { @@ -3415,7 +2833,7 @@ void check_samples() struct POSIX_ACE ace[6]; } sampletry5 = { - { 0454, 6, 0, 6, 0x3f, + { 0454, 6, 0, 6, 0x3f, 0, { POSIX_VERSION, 0, 0 } }, { @@ -3433,7 +2851,7 @@ void check_samples() struct POSIX_ACE ace[8]; } sampletry6 = { - { 0332, 8, 0, 8, 0x3f, + { 0332, 8, 0, 8, 0x3f, 0, { POSIX_VERSION, 0, 0 } }, { @@ -3453,7 +2871,7 @@ void check_samples() struct POSIX_ACE ace[4]; } sampletry8 = { - { 0677, 4, 0, 4, 0x35, + { 0677, 4, 0, 4, 0x35, 0, { POSIX_VERSION, 0, 0 } }, { @@ -3536,10 +2954,12 @@ void check_samples() else pxdesc = (struct POSIX_SECURITY*)NULL; if (!descr || !pxdesc || !same_posix(pxsample,pxdesc)) { - printf("** Error in %s\n",txsample); + printf("** Error in %s (errno %d)\n",txsample,errno); showposix(pxsample); - showall(descr,0); - showposix(pxdesc); + if (descr) + showall(descr,0); + if (pxdesc) + showposix(pxdesc); errors++; } free(descr); @@ -3562,7 +2982,7 @@ void check_samples() (const SID*)owner1, (const SID*)group1, 1, (int)TRUE, worldsid, (int)0x3, (u32)0x1f01ff); - expectacc = expect = 0777; + expect = expectacc = 0777; expectdef = 0; break; case 2 : /* swsetup */ @@ -3586,7 +3006,7 @@ void check_samples() descr = build_dummy_descr(isdir, (const SID*)owner3, (const SID*)group3, 4, - (int)TRUE, (const SID*)owner3, 0, + (int)TRUE, (const SID*)owner3, 0, le32_to_cpu(FILE_READ_DATA | OWNER_RIGHTS), (int)TRUE, (const SID*)group3, 0, le32_to_cpu(FILE_WRITE_DATA), @@ -3623,8 +3043,7 @@ void check_samples() (int)TRUE, adminsid, (int)0xb, (u32)0x1f01ff, (int)TRUE, owner3, (int)0x3, (u32)0x1200a9); expectacc = 0500070700; - expectdef = 0700; - expect = 0700; + expectdef = expect = 0700; break; case 7 : /* WinXP/JP */ isdir = TRUE; @@ -3710,11 +3129,10 @@ void check_samples() (long)defrights,(long)expectdef); showall(descr,0); showposix(pxdesc); -exit(1); } free(pxdesc); } -#endif +#endif /* POSIXACLS */ } free(descr); } @@ -3727,7 +3145,7 @@ exit(1); * back exactly as set */ -void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) +static void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) { char *attr; mode_t perm; @@ -3761,7 +3179,7 @@ void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) u32 pxcount; u32 pxacecount; u32 pxglobhash; -#endif +#endif /* POSIXACLS */ count = 0; acecount = 0; @@ -3770,7 +3188,7 @@ void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) pxcount = 0; pxacecount = 0; pxglobhash = 0; -#endif +#endif /* POSIXACLS */ for (perm=0; (perm<=07777) && (errors < 10); perm++) { err = ERRNO; /* file owned by plain user and group */ @@ -3820,7 +3238,7 @@ void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) free(attr); } free(pxdesc); -#else +#else /* POSIXACLS */ gotback = linux_permissions(attr, isdir); if (gotback != perm) err = ERRAM; @@ -3868,7 +3286,7 @@ void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) break; case ERRAP : /* continued */ -#else +#else /* POSIXACLS */ case ERRAM : case ERRAP : #endif /* POSIXACLS */ @@ -3930,7 +3348,7 @@ void basictest(int kind, BOOL isdir, const SID *owner, const SID *group) * back exactly as set */ -void posixtest(int kind, BOOL isdir, +static void posixtest(int kind, BOOL isdir, const SID *owner, const SID *group) { struct POSIX_SECURITY *pxdesc; @@ -3956,23 +3374,8 @@ void posixtest(int kind, BOOL isdir, enum { ERRNO, ERRMA, ERRPA, /* error converting mode or Posix ACL to NTFS */ ERRAM, ERRAP, /* error converting NTFS to mode or Posix ACL */ - } err; + } ; u32 expectcnt[] = { -#ifdef STSC - 32400, 34992, - 25920, 28512, - 25920, 28512, - 25920, 28512, - 26460, 29052, - 0, 0, - 0, 0, - 0, 0, - 24516, 27108, - 20736, 23328, - 20736, 23328, - 20736, 23328, - 21060, 23652, -#else 252720, 273456, 199584, 220320, 199584, 220320, @@ -3986,7 +3389,6 @@ void posixtest(int kind, BOOL isdir, 165888, 186624, 165888, 186624, 168480, 189216, -#endif 0, 0, 0, 0, 0, 0, @@ -3997,21 +3399,6 @@ void posixtest(int kind, BOOL isdir, 14640, 0 } ; u32 expecthash[] = { -#ifdef STSC - 0xf9f82115, 0x40666647, - 0xde826d30, 0xa181b660, - 0x952d4500, 0x8ac49450, - 0xf80acee0, 0xbd9ec6c0, - 0xfe09b868, 0xde24e84d, - 0, 0, - 0, 0, - 0, 0, - 0x2381438d, 0x3ab42dc6, - 0x7cccf6f8, 0x108ad430, - 0x5e448840, 0x83ab6c40, - 0x9b037100, 0x8f7c3b40, - 0x04a359dc, 0xa4619609, -#else 0x1808a6cd, 0xd82f7c60, 0x5ad29e85, 0x518c7620, 0x188ce270, 0x7e44e590, @@ -4025,7 +3412,6 @@ void posixtest(int kind, BOOL isdir, 0xf9685700, 0x44d16700, 0x587ebe90, 0xf7c51480, 0x2cb1b518, 0x52408df6, -#endif 0, 0, 0, 0, 0, 0, @@ -4080,13 +3466,8 @@ void posixtest(int kind, BOOL isdir, mindes = 3; maxdes = (kind & 32 ? mindes : 6); -#ifdef STSC - minmsk = (kind & 32 ? 0 : 3); - maxmsk = (kind & 32 ? 7 : 3); -#else minmsk = 0; maxmsk = 7; -#endif for (mask=minmsk; mask<=maxmsk; mask++) for (ownobj=1; ownobj<7; ownobj++) for (grpobj=1; grpobj<7; grpobj++) @@ -4110,7 +3491,6 @@ void posixtest(int kind, BOOL isdir, pxdesc->acl.ace[5].perms = wrld; } - err = ERRNO; gotback = (struct POSIX_SECURITY*)NULL; pxattr = ntfs_build_descr_posix(context.mapping, pxdesc,isdir,owner,group); @@ -4136,7 +3516,6 @@ void posixtest(int kind, BOOL isdir, printf("gotback ACL\n"); showposix(gotback); errors++; -exit(1); } } else { printf("Got back an invalid Posix ACL\n"); @@ -4184,32 +3563,24 @@ exit(1); #endif /* POSIXACLS */ -void selftests(void) +static void selftests(void) { le32 owner_sid[] = /* S-1-5-21-3141592653-589793238-462843383-1016 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), - const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), - const_cpu_to_le32(1016) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(DEFSECAUTH1), cpu_to_le32(DEFSECAUTH2), + cpu_to_le32(DEFSECAUTH3), cpu_to_le32(1016) } ; le32 group_sid[] = /* S-1-5-21-3141592653-589793238-462843383-513 */ { - const_cpu_to_le32(0x501), const_cpu_to_le32(0x05000000), - const_cpu_to_le32(21), const_cpu_to_le32(DEFSECAUTH1), - const_cpu_to_le32(DEFSECAUTH2), const_cpu_to_le32(DEFSECAUTH3), - const_cpu_to_le32(513) + cpu_to_le32(0x501), cpu_to_le32(0x05000000), cpu_to_le32(21), + cpu_to_le32(DEFSECAUTH1), cpu_to_le32(DEFSECAUTH2), + cpu_to_le32(DEFSECAUTH3), cpu_to_le32(513) } ; #if POSIXACLS -#ifdef STSC - unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 16, 17, 18, 20, 22, 24, - 32, 33, 36, 40 } ; -#else unsigned char kindlist[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 20, 22, 24, 19, 21, 23, 25, 32, 33, 36, 40 } ; -#endif unsigned int k; #endif /* POSIXACLS */ int kind; @@ -4219,11 +3590,10 @@ void selftests(void) #if POSIXACLS local_build_mapping(context.mapping, (const char*)NULL); -#endif +#endif /* POSIXACLS */ /* first check samples */ mappingtype = MAPDUMMY; check_samples(); -if (errors) exit(1); /* * kind is oring of : * 1 : directory @@ -4254,202 +3624,17 @@ if (errors) exit(1); posixtest(kind, isdir, owner, group); } ntfs_free_mapping(context.mapping); -#endif +#endif /* POSIXACLS */ if (errors >= 10) printf("** too many errors, test aborted\n"); } -#endif /* SELFTESTS & !USESTUBS */ - -#ifdef WIN32 +#endif /* SELFTESTS */ /* - * Get the security descriptor of a file (Windows version) + * Get the security descriptor of a file */ -unsigned int getfull(char *attr, const char *fullname) -{ - static char part[MAXATTRSZ]; - BIGSID ownsid; - int xowner; - int ownersz; - u16 ownerfl; - ULONG attrsz; - ULONG partsz; - BOOL overflow; - HANDLE htoken; - TOKEN_PRIVILEGES tkp; - BOOL saclsuccess; - - attrsz = 0; - partsz = 0; - overflow = FALSE; - if (GetFileSecurityW((LPCWSTR)fullname,OWNER_SECURITY_INFORMATION, - (char*)part,MAXATTRSZ,&partsz)) { - xowner = get4l(part,4); - if (xowner) { - ownerfl = get2l(part,2); - ownersz = ntfs_sid_size((SID*)&part[xowner]); - if (ownersz <= (int)sizeof(BIGSID)) - memcpy(ownsid,&part[xowner],ownersz); - else - overflow = TRUE; - } else { - ownerfl = 0; - ownersz = 0; - } - /* - * SACL : just feed in or clean - * This requires the SE_SECURITY_NAME privilege - */ - saclsuccess = FALSE; - if (OpenProcessToken(GetCurrentProcess(), - TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &htoken)) { - if (LookupPrivilegeValue(NULL, SE_SECURITY_NAME, - &tkp.Privileges[0].Luid)) { - tkp.PrivilegeCount = 1; - tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - if (AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0)) { - if (GetFileSecurityW((LPCWSTR)fullname, - SACL_SECURITY_INFORMATION, - (char*)attr,MAXATTRSZ,&attrsz)) { - saclsuccess = TRUE; - } - tkp.Privileges[0].Attributes = 0; - AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, 0); - } - } - } - if (!saclsuccess) { - attrsz = 20; - set4l(attr,0); - attr[0] = SECURITY_DESCRIPTOR_REVISION; - set4l(&attr[12],0); - if (opt_v >= 2) - printf(" No SACL\n"); - } - /* - * append DACL and merge its flags - */ - partsz = 0; - set4l(&attr[16],0); - if (GetFileSecurityW((LPCWSTR)fullname,DACL_SECURITY_INFORMATION, - (char*)part,MAXATTRSZ,&partsz)) { - if ((attrsz + partsz - 20) <= MAXATTRSZ) { - memcpy(&attr[attrsz],&part[20],partsz-20); - set4l(&attr[16],(partsz > 20 ? attrsz : 0)); - set2l(&attr[2],get2l(attr,2) | (get2l(part,2) - & const_le16_to_cpu(SE_DACL_PROTECTED - | SE_DACL_AUTO_INHERITED - | SE_DACL_PRESENT))); - attrsz += partsz - 20; - } else - overflow = TRUE; - } else - if (partsz > MAXATTRSZ) - overflow = TRUE; - else { - if (opt_b) - printf("# No discretionary access control list\n"); - else - printf(" No discretionary access control list\n"); - warnings++; - } - - /* - * append owner and merge its flag - */ - if (xowner && !overflow) { - memcpy(&attr[attrsz],ownsid,ownersz); - set4l(&attr[4],attrsz); - set2l(&attr[2],get2l(attr,2) - | (ownerfl & const_le16_to_cpu(SE_OWNER_DEFAULTED))); - attrsz += ownersz; - } else - set4l(&attr[4],0); - /* - * append group - */ - partsz = 0; - set4l(&attr[8],0); - if (GetFileSecurityW((LPCWSTR)fullname,GROUP_SECURITY_INFORMATION, - (char*)part,MAXATTRSZ,&partsz)) { - if ((attrsz + partsz - 20) <= MAXATTRSZ) { - memcpy(&attr[attrsz],&part[20],partsz-20); - set4l(&attr[8],(partsz > 20 ? attrsz : 0)); - set2l(&attr[2],get2l(attr,2) | (get2l(part,2) - & const_le16_to_cpu(SE_GROUP_DEFAULTED))); - attrsz += partsz - 20; - } else - overflow = TRUE; - } else - if (partsz > MAXATTRSZ) - overflow = TRUE; - else { - printf("** No group SID\n"); - warnings++; - } - set2l(&attr[2],get2l(attr,2) - | const_le16_to_cpu(SE_SELF_RELATIVE)); - if (overflow) { - printf("** Descriptor was too long (> %d)\n",MAXATTRSZ); - warnings++; - attrsz = 0; - } else - if (!ntfs_valid_descr((char*)attr,attrsz)) { - printf("** Descriptor for "); - printname(stdout,fullname); - printf(" is not valid\n"); - errors++; - attrsz = 0; - } - - } else { - printf("** Could not get owner of "); - printname(stdout,fullname); - printf(", partsz %d\n",partsz); - printerror(stdout); - warnings++; - attrsz = 0; - } - return (attrsz); -} - -/* - * Update a security descriptor (Windows version) - */ - -BOOL updatefull(const char *name, DWORD flags, char *attr) -{ - BOOL bad; - - bad = !SetFileSecurityW((LPCWSTR)name, flags, attr); - if (bad - && (flags & OWNER_SECURITY_INFORMATION) - && (GetLastError() == 1307)) { - printf("** Could not set owner of "); - printname(stdout,name); - printf(", retrying with no owner setting\n"); - warnings++; - bad = !SetFileSecurityW((LPCWSTR)name, - flags & ~OWNER_SECURITY_INFORMATION, (char*)attr); - } - if (bad) { - printf("** Could not change attributes of "); - printname(stdout,name); - printf("\n"); - printerror(stdout); - errors++; - } - return (!bad); -} - -#else - -/* - * Get the security descriptor of a file (Linux version) - */ - -unsigned int getfull(char *attr, const char *fullname) +static unsigned int getfull(char *attr, const char *fullname) { static char part[MAXATTRSZ]; BIGSID ownsid; @@ -4513,7 +3698,7 @@ unsigned int getfull(char *attr, const char *fullname) if (partsz > MAXATTRSZ) overflow = TRUE; else { - if (opt_b) + if (cmd == CMD_BACKUP) printf("# No discretionary access control list\n"); else printf(" No discretionary access control list\n"); @@ -4568,38 +3753,37 @@ unsigned int getfull(char *attr, const char *fullname) } else { printf("** Could not get owner of %s\n",fullname); warnings++; - attrsz = 0; + attrsz = 0; } return (attrsz); } /* - * Update a security descriptor (Linux version) + * Update a security descriptor */ -BOOL updatefull(const char *name, DWORD flags, char *attr) +static BOOL updatefull(const char *name, u32 flags, char *attr) { - BOOL ok; + BOOL err; - ok = !ntfs_set_file_security(ntfs_context, name, flags, attr); - if (ok) { +// Why was the error not seen before ? + err = !ntfs_set_file_security(ntfs_context, name, flags, attr); + if (err) { printf("** Could not change attributes of %s\n",name); printerror(stdout); errors++; } - return (ok); + return (!err); } -#endif - #if POSIXACLS /* * Set all the parameters associated to a file */ -BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc, +static BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc, BOOL isdir) { static char attr[MAXATTRSZ]; @@ -4614,7 +3798,7 @@ BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc, const SID *gsid; #if OWNERFROMACL const SID *osid; -#endif +#endif /* OWNERFROMACL */ printf("%s ",(isdir ? "Directory" : "File")); printname(stdout,fullname); @@ -4658,12 +3842,18 @@ BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc, osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; usid = ntfs_acl_owner((const char*)attr); if (!ntfs_same_sid(usid,osid)) - printf("== Windows owner might change\n"); -#else + printf("== Windows owner might change\n"); +#else /* OWNERFROMACL */ usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; -#endif - newattr = ntfs_build_descr_posix(context.mapping, - newpxdesc,isdir,usid,gsid); +#endif /* OWNERFROMACL */ + if (mappingtype == MAPEXTERN) + newattr = ntfs_build_descr_posix( + ntfs_context->security.mapping, + newpxdesc,isdir,usid,gsid); + else + newattr = ntfs_build_descr_posix( + context.mapping, + newpxdesc,isdir,usid,gsid); free(newpxdesc); } else newattr = (char*)NULL; @@ -4683,23 +3873,11 @@ BOOL setfull_posix(const char *fullname, const struct POSIX_SECURITY *pxdesc, showsacl(newattr,isdir,0); } -#ifdef WIN32 - /* - * avoid getting a set owner error on Windows - * owner should not be changed anyway - */ if (!updatefull(fullname, DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, newattr)) -#else - if (!updatefull(fullname, - DACL_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | OWNER_SECURITY_INFORMATION, - newattr)) -#endif err = TRUE; /* { @@ -4718,9 +3896,9 @@ free(interp); return (!err); } -#endif +#else /* POSIXACLS */ -BOOL setfull(const char *fullname, int mode, BOOL isdir) +static BOOL setfull(const char *fullname, int mode, BOOL isdir) { static char attr[MAXATTRSZ]; const SECURITY_DESCRIPTOR_RELATIVE *phead; @@ -4732,7 +3910,7 @@ BOOL setfull(const char *fullname, int mode, BOOL isdir) const SID *gsid; #if OWNERFROMACL const SID *osid; -#endif +#endif /* OWNERFROMACL */ printf("%s ",(isdir ? "Directory" : "File")); printname(stdout,fullname); @@ -4746,10 +3924,10 @@ BOOL setfull(const char *fullname, int mode, BOOL isdir) osid = (const SID*)&attr[le32_to_cpu(phead->owner)]; usid = ntfs_acl_owner((const char*)attr); if (!ntfs_same_sid(usid,osid)) - printf("== Windows owner might change\n"); -#else + printf("== Windows owner might change\n"); +#else /* OWNERFROMACL */ usid = (const SID*)&attr[le32_to_cpu(phead->owner)]; -#endif +#endif /* OWNERFROMACL */ newattr = ntfs_build_descr(mode,isdir,usid,gsid); if (newattr) { newattrsz = ntfs_attr_size(newattr); @@ -4767,33 +3945,23 @@ BOOL setfull(const char *fullname, int mode, BOOL isdir) showsacl(newattr,isdir,0); } -#ifdef WIN32 - /* - * avoid getting a set owner error on Windows - * owner should not be changed anyway - */ if (!updatefull(fullname, DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, newattr)) -#else - if (!updatefull(fullname, - DACL_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | OWNER_SECURITY_INFORMATION, - newattr)) -#endif err = TRUE; free(newattr); } - + } else err = TRUE; return (err); } -BOOL proposal(const char *name, const char *attr) +#endif /* POSIXACLS */ + +static BOOL proposal(const char *name, const char *attr) { char fullname[MAXFILENAME]; int uoff, goff; @@ -4802,20 +3970,20 @@ BOOL proposal(const char *name, const char *attr) int ucnt, gcnt; int uid, gid; BOOL err; -#ifdef WIN32 +#ifdef HAVE_WINDOWS_H char driveletter; -#else +#else /* HAVE_WINDOWS_H */ struct stat st; char *p,*q; -#endif +#endif /* HAVE_WINDOWS_H */ err = FALSE; -#ifdef WIN32 +#ifdef HAVE_WINDOWS_H uid = gid = 0; -#else +#else /* HAVE_WINDOWS_H */ uid = getuid(); gid = getgid(); -#endif +#endif /* HAVE_WINDOWS_H */ uoff = get4l(attr,4); uauth = get6h(attr,uoff+2); ucnt = attr[uoff+1] & 255; @@ -4832,7 +4000,7 @@ BOOL proposal(const char *name, const char *attr) printf("%d::",uid); else printf("user::"); - printf("S-%d-%llu",attr[uoff] & 255,uauth); + printf("S-%d-%llu",attr[uoff] & 255,(long long)uauth); for (i=0; i