Merge tag '2021.8.22' into edge.strict_endians
Conflicts: libntfs-3g/attrib.c libntfs-3g/bootsect.c ntfsprogs/ntfsfix.cedge.strict_endians
						commit
						11a3997a0d
					
				| 
						 | 
				
			
			@ -1,6 +1,3 @@
 | 
			
		|||
ChangeLog can be found at :
 | 
			
		||||
 | 
			
		||||
Detailed ChangeLog can be found at
 | 
			
		||||
	http://www.tuxera.com/community/release-history/
 | 
			
		||||
 | 
			
		||||
The changes and history may also be found on the source repository :
 | 
			
		||||
	http://sourceforge.net/p/ntfs-3g/ntfs-3g/ci/edge/tree/
 | 
			
		||||
        https://github.com/tuxera/ntfs-3g/wiki
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								NEWS
								
								
								
								
							
							
						
						
									
										6
									
								
								NEWS
								
								
								
								
							| 
						 | 
				
			
			@ -1,5 +1,3 @@
 | 
			
		|||
Project information can be found at :
 | 
			
		||||
 | 
			
		||||
Project news are at http://tuxera.com/community/ntfs-3g-download/
 | 
			
		||||
 | 
			
		||||
Release notes are maintained at http://tuxera.com/community/release-history/
 | 
			
		||||
 | 
			
		||||
        https://github.com/tuxera/ntfs-3g/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										43
									
								
								README
								
								
								
								
							
							
						
						
									
										43
									
								
								README
								
								
								
								
							| 
						 | 
				
			
			@ -3,9 +3,10 @@ INTRODUCTION
 | 
			
		|||
============
 | 
			
		||||
 | 
			
		||||
The NTFS-3G driver is an open source, freely available read/write NTFS driver 
 | 
			
		||||
for Linux, FreeBSD, Mac OS X, NetBSD, OpenSolaris, QNX and Haiku. It provides 
 | 
			
		||||
for Linux, FreeBSD, macOS, NetBSD, OpenIndiana, QNX and Haiku. It provides 
 | 
			
		||||
safe and fast handling of the Windows XP, Windows Server 2003, Windows 2000, 
 | 
			
		||||
Windows Vista, Windows Server 2008 and Windows 7 file systems. 
 | 
			
		||||
Windows Vista, Windows Server 2008, Windows 7, Windows 8, Windows Server 2012,
 | 
			
		||||
Windows Server 2016, Windows 10 and Windows Server 2019 NTFS file systems.
 | 
			
		||||
 | 
			
		||||
The purpose of the project is to develop, quality assurance and support a 
 | 
			
		||||
trustable, featureful and high performance solution for hardware platforms 
 | 
			
		||||
| 
						 | 
				
			
			@ -18,21 +19,22 @@ Besides the common file system features, NTFS-3G has support for file
 | 
			
		|||
ownership and permissions, POSIX ACLs, junction points, extended attributes 
 | 
			
		||||
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/
 | 
			
		||||
available in Windows 10 can also be read through a plugin. 
 | 
			
		||||
 | 
			
		||||
News, support answers, problem submission instructions, support and discussion 
 | 
			
		||||
forums, performance numbers and other information are available on the project 
 | 
			
		||||
web site at
 | 
			
		||||
forums, and other information are available on the project web site at
 | 
			
		||||
 | 
			
		||||
	https://github.com/tuxera/ntfs-3g
 | 
			
		||||
 | 
			
		||||
The project has been funded, supported and maintained since 2008 by Tuxera:
 | 
			
		||||
 | 
			
		||||
	https://tuxera.com
 | 
			
		||||
 | 
			
		||||
	http://www.tuxera.com/community/
 | 
			
		||||
 | 
			
		||||
LICENSES
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
All the NTFS related components : the file system drivers, the ntfsprogs
 | 
			
		||||
All the NTFS related components: the file system drivers, the ntfsprogs
 | 
			
		||||
utilities and the shared library libntfs-3g are distributed under the terms
 | 
			
		||||
of the GNU General Public License as published by the Free Software
 | 
			
		||||
Foundation; either version 2 of the License, or (at your option) any later
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +43,7 @@ version. See the included file COPYING.
 | 
			
		|||
The fuse-lite library is distributed under the terms of the GNU LGPLv2.
 | 
			
		||||
See the included file COPYING.LIB.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QUICK INSTALLATION
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -73,12 +76,6 @@ There are also a few make targets for building parts :
 | 
			
		|||
	make drivers : only build drivers and libraries, without ntfsprogs
 | 
			
		||||
	make ntfsprogs : only build ntfsprogs and libntfs-3g, without drivers
 | 
			
		||||
 | 
			
		||||
Non-Linux: Please see 
 | 
			
		||||
 | 
			
		||||
	http://www.tuxera.com/community/ntfs-3g-download/
 | 
			
		||||
 | 
			
		||||
for known OS specific installation and source packages, but generally
 | 
			
		||||
the same procedures apply.
 | 
			
		||||
 | 
			
		||||
USAGE
 | 
			
		||||
=====
 | 
			
		||||
| 
						 | 
				
			
			@ -106,23 +103,23 @@ TESTING WITHOUT INSTALLING
 | 
			
		|||
Newer versions of ntfs-3g can be tested without installing anything and
 | 
			
		||||
without disturbing an existing installation. Just configure and make as
 | 
			
		||||
shown previously. This will create the scripts ntfs-3g and lowntfs-3g
 | 
			
		||||
in the src directory, which you may activate for testing :
 | 
			
		||||
in the src directory, which you may activate for testing:
 | 
			
		||||
 | 
			
		||||
	./configure
 | 
			
		||||
	make
 | 
			
		||||
 | 
			
		||||
then, as root :
 | 
			
		||||
then, as root:
 | 
			
		||||
	src/ntfs-3g [-o mount-options] /dev/sda1 /mnt/windows
 | 
			
		||||
 | 
			
		||||
And, to end the test, unmount the usual way :
 | 
			
		||||
And, to end the test, unmount the usual way:
 | 
			
		||||
	umount /dev/sda1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
NTFS UTILITIES
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
The ntfsprogs includes utilities for doing all required tasks to NTFS 
 | 
			
		||||
partitions.  In general, just run a utility without any command line
 | 
			
		||||
The ntfsprogs directory includes utilities for doing all required tasks to
 | 
			
		||||
NTFS partitions. In general, just run a utility without any command line
 | 
			
		||||
options to display the version number and usage syntax.
 | 
			
		||||
 | 
			
		||||
The following utilities are so far implemented:
 | 
			
		||||
| 
						 | 
				
			
			@ -159,6 +156,6 @@ ntfscat - Concatenate files and print their contents on the standard output.
 | 
			
		|||
 | 
			
		||||
ntfscp - Overwrite files on an NTFS partition.
 | 
			
		||||
 | 
			
		||||
ntfssecaudit : audit the security metadata.
 | 
			
		||||
ntfssecaudit - Audit the security metadata.
 | 
			
		||||
 | 
			
		||||
ntfsusermap : assistance for building a user mapping file.
 | 
			
		||||
ntfsusermap - Assistance for building a user mapping file.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,8 +24,8 @@
 | 
			
		|||
 | 
			
		||||
# Autoconf
 | 
			
		||||
AC_PREREQ(2.59)
 | 
			
		||||
AC_INIT([ntfs-3g],[2017.3.23],[ntfs-3g-devel@lists.sf.net])
 | 
			
		||||
LIBNTFS_3G_VERSION="88"
 | 
			
		||||
AC_INIT([ntfs-3g],[2021.8.22],[ntfs-3g-devel@lists.sf.net])
 | 
			
		||||
LIBNTFS_3G_VERSION="89"
 | 
			
		||||
AC_CONFIG_SRCDIR([src/ntfs-3g.c])
 | 
			
		||||
 | 
			
		||||
# Environment
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -398,6 +398,7 @@ extern int ntfs_attr_data_write(ntfs_inode *ni,
 | 
			
		|||
		const char *buf, size_t size, off_t offset);
 | 
			
		||||
extern int ntfs_attr_shrink_size(ntfs_inode *ni, ntfschar *stream_name,
 | 
			
		||||
		int stream_name_len, off_t offset);
 | 
			
		||||
extern int ntfs_attr_inconsistent(const ATTR_RECORD *a, const MFT_REF mref);
 | 
			
		||||
 | 
			
		||||
#endif /* defined _NTFS_ATTRIB_H */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -139,6 +139,10 @@ extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
 | 
			
		|||
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
 | 
			
		||||
extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx);
 | 
			
		||||
 | 
			
		||||
extern int ntfs_index_block_inconsistent(const INDEX_BLOCK *ib, u32 block_size,
 | 
			
		||||
			u64 inum, VCN vcn);
 | 
			
		||||
extern int ntfs_index_entry_inconsistent(const INDEX_ENTRY *ie,
 | 
			
		||||
			COLLATION_RULES collation_rule, u64 inum);
 | 
			
		||||
extern int ntfs_index_lookup(const void *key, const int key_len,
 | 
			
		||||
		ntfs_index_context *ictx) __attribute_warn_unused_result__;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,6 +117,7 @@ typedef enum {
 | 
			
		|||
	NV_HideDotFiles,	/* 1: Set hidden flag on dot files */
 | 
			
		||||
	NV_Compression,		/* 1: allow compression */
 | 
			
		||||
	NV_NoFixupWarn,		/* 1: Do not log fixup errors */
 | 
			
		||||
	NV_FreeSpaceKnown,	/* 1: The free space is now known */
 | 
			
		||||
} ntfs_volume_state_bits;
 | 
			
		||||
 | 
			
		||||
#define  test_nvol_flag(nv, flag)	 test_bit(NV_##flag, (nv)->state)
 | 
			
		||||
| 
						 | 
				
			
			@ -155,6 +156,10 @@ typedef enum {
 | 
			
		|||
#define NVolSetNoFixupWarn(nv)		  set_nvol_flag(nv, NoFixupWarn)
 | 
			
		||||
#define NVolClearNoFixupWarn(nv)	clear_nvol_flag(nv, NoFixupWarn)
 | 
			
		||||
 | 
			
		||||
#define NVolFreeSpaceKnown(nv)		 test_nvol_flag(nv, FreeSpaceKnown)
 | 
			
		||||
#define NVolSetFreeSpaceKnown(nv)	  set_nvol_flag(nv, FreeSpaceKnown)
 | 
			
		||||
#define NVolClearFreeSpaceKnown(nv)	clear_nvol_flag(nv, FreeSpaceKnown)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * NTFS version 1.1 and 1.2 are used by Windows NT4.
 | 
			
		||||
 * NTFS version 2.x is used by Windows 2000 Beta
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1330,6 +1330,10 @@ struct POSIX_SECURITY *ntfs_build_basic_posix(
 | 
			
		|||
		pydesc->acccnt = 3;
 | 
			
		||||
		pydesc->defcnt = 0;
 | 
			
		||||
		pydesc->firstdef = 6;
 | 
			
		||||
		pydesc->filler = 0;
 | 
			
		||||
		pydesc->acl.version = POSIX_VERSION;
 | 
			
		||||
		pydesc->acl.flags = 0;
 | 
			
		||||
		pydesc->acl.filler = 0;
 | 
			
		||||
	} else
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
	return (pydesc);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
 * Copyright (c) 2002-2005 Richard Russon
 | 
			
		||||
 * Copyright (c) 2002-2008 Szabolcs Szakacsits
 | 
			
		||||
 * Copyright (c) 2004-2007 Yura Pakhuchiy
 | 
			
		||||
 * Copyright (c) 2007-2020 Jean-Pierre Andre
 | 
			
		||||
 * Copyright (c) 2007-2021 Jean-Pierre Andre
 | 
			
		||||
 * Copyright (c) 2010      Erik Larsson
 | 
			
		||||
 *
 | 
			
		||||
 * This program/include file is free software; you can redistribute it and/or
 | 
			
		||||
| 
						 | 
				
			
			@ -489,6 +489,17 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (a->non_resident) {
 | 
			
		||||
		if ((!le16_andz(a->flags, ATTR_COMPRESSION_MASK)
 | 
			
		||||
			|| a->compression_unit)
 | 
			
		||||
		    && (ni->vol->major_ver < 3)) {
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			ntfs_log_perror("Compressed inode %lld not allowed"
 | 
			
		||||
					" on NTFS %d.%d",
 | 
			
		||||
					(unsigned long long)ni->mft_no,
 | 
			
		||||
					ni->vol->major_ver,
 | 
			
		||||
					ni->vol->major_ver);
 | 
			
		||||
			goto put_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		if (!le16_andz(a->flags, ATTR_COMPRESSION_MASK)
 | 
			
		||||
				 && !a->compression_unit) {
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
| 
						 | 
				
			
			@ -497,6 +508,17 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
 | 
			
		|||
					(unsigned long long)ni->mft_no, le32_to_cpu(type));
 | 
			
		||||
			goto put_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		if (!le16_andz(a->flags, ATTR_COMPRESSION_MASK)
 | 
			
		||||
				 && (a->compression_unit
 | 
			
		||||
					!= STANDARD_COMPRESSION_UNIT)) {
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			ntfs_log_perror("Compressed inode %lld attr 0x%lx has "
 | 
			
		||||
					"an unsupported compression unit %d",
 | 
			
		||||
					(unsigned long long)ni->mft_no,
 | 
			
		||||
					(long)le32_to_cpu(type),
 | 
			
		||||
					(int)a->compression_unit);
 | 
			
		||||
			goto put_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		ntfs_attr_init(na, TRUE, a->flags,
 | 
			
		||||
				!le16_andz(a->flags, ATTR_IS_ENCRYPTED),
 | 
			
		||||
				!le16_andz(a->flags, ATTR_IS_SPARSE),
 | 
			
		||||
| 
						 | 
				
			
			@ -1256,6 +1278,17 @@ static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs,
 | 
			
		|||
	LCN lcn_seek_from = -1;
 | 
			
		||||
	VCN cur_vcn, from_vcn;
 | 
			
		||||
 | 
			
		||||
	if (na->ni->mft_no == FILE_Bitmap) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Filling a hole in the main bitmap implies allocating
 | 
			
		||||
		 * clusters, which is likely to imply updating the
 | 
			
		||||
		 * bitmap in a cluster being allocated.
 | 
			
		||||
		 * Not supported now, could lead to endless recursions.
 | 
			
		||||
		 */
 | 
			
		||||
		ntfs_log_error("Corrupt $BitMap not fully allocated\n");
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
	to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs);
 | 
			
		||||
	
 | 
			
		||||
	cur_vcn = (*rl)->vcn;
 | 
			
		||||
| 
						 | 
				
			
			@ -2765,6 +2798,8 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name,
 | 
			
		|||
	ATTR_RECORD *a;
 | 
			
		||||
	ntfs_volume *vol;
 | 
			
		||||
	ntfschar *upcase;
 | 
			
		||||
	ptrdiff_t offs;
 | 
			
		||||
	ptrdiff_t space;
 | 
			
		||||
	u32 upcase_len;
 | 
			
		||||
 | 
			
		||||
	ntfs_log_trace("attribute type 0x%x.\n", le32_to_cpu(type));
 | 
			
		||||
| 
						 | 
				
			
			@ -2794,8 +2829,17 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name,
 | 
			
		|||
		a = (ATTR_RECORD*)((char*)ctx->attr +
 | 
			
		||||
				le32_to_cpu(ctx->attr->length));
 | 
			
		||||
	for (;;	a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
 | 
			
		||||
		if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec +
 | 
			
		||||
				le32_to_cpu(ctx->mrec->bytes_allocated))
 | 
			
		||||
		/*
 | 
			
		||||
		 * Make sure the attribute fully lies within the MFT record
 | 
			
		||||
		 * and we can safely access its minimal fields.
 | 
			
		||||
		 */
 | 
			
		||||
		offs = p2n(a) - p2n(ctx->mrec);
 | 
			
		||||
		space = le32_to_cpu(ctx->mrec->bytes_in_use) - offs;
 | 
			
		||||
		if ((offs < 0)
 | 
			
		||||
		    || (((space < (ptrdiff_t)offsetof(ATTR_RECORD,
 | 
			
		||||
						resident_end))
 | 
			
		||||
			|| (space < (ptrdiff_t)le32_to_cpu(a->length)))
 | 
			
		||||
			    && ((space < 4) || !le32_eq(a->type, AT_END))))
 | 
			
		||||
			break;
 | 
			
		||||
		ctx->attr = a;
 | 
			
		||||
		if ((!le32_eq(type, AT_UNUSED) && (le32_to_cpu(a->type) >
 | 
			
		||||
| 
						 | 
				
			
			@ -2824,6 +2868,16 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name,
 | 
			
		|||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			register int rc;
 | 
			
		||||
 | 
			
		||||
			if (a->name_length
 | 
			
		||||
			    && ((le16_to_cpu(a->name_offset)
 | 
			
		||||
					+ a->name_length * sizeof(ntfschar))
 | 
			
		||||
					> le32_to_cpu(a->length))) {
 | 
			
		||||
				ntfs_log_error("Corrupt attribute name"
 | 
			
		||||
					" in MFT record %lld\n",
 | 
			
		||||
					(long long)ctx->ntfs_ino->mft_no);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			if (name && ((rc = ntfs_names_full_collate(name,
 | 
			
		||||
					name_len, (ntfschar*)((char*)a +
 | 
			
		||||
						le16_to_cpu(a->name_offset)),
 | 
			
		||||
| 
						 | 
				
			
			@ -2986,6 +3040,8 @@ static int ntfs_external_attr_find(ATTR_TYPES type, const ntfschar *name,
 | 
			
		|||
	u8 *al_start, *al_end;
 | 
			
		||||
	ATTR_RECORD *a;
 | 
			
		||||
	ntfschar *al_name;
 | 
			
		||||
	ptrdiff_t offs;
 | 
			
		||||
	ptrdiff_t space;
 | 
			
		||||
	u32 al_name_len;
 | 
			
		||||
	BOOL is_first_search = FALSE;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3026,8 +3082,22 @@ static int ntfs_external_attr_find(ATTR_TYPES type, const ntfschar *name,
 | 
			
		|||
				le32_to_cpu(AT_ATTRIBUTE_LIST))
 | 
			
		||||
			goto find_attr_list_attr;
 | 
			
		||||
	} else {
 | 
			
		||||
			/* Check for small entry */
 | 
			
		||||
		if (((p2n(al_end) - p2n(ctx->al_entry))
 | 
			
		||||
				< (long)offsetof(ATTR_LIST_ENTRY, name))
 | 
			
		||||
		    || (le16_to_cpu(ctx->al_entry->length) & 7)
 | 
			
		||||
		    || (le16_to_cpu(ctx->al_entry->length)
 | 
			
		||||
				< offsetof(ATTR_LIST_ENTRY, name)))
 | 
			
		||||
			goto corrupt;
 | 
			
		||||
 | 
			
		||||
		al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry +
 | 
			
		||||
				le16_to_cpu(ctx->al_entry->length));
 | 
			
		||||
		if ((u8*)al_entry == al_end)
 | 
			
		||||
			goto not_found;
 | 
			
		||||
			/* Preliminary check for small entry */
 | 
			
		||||
		if ((p2n(al_end) - p2n(al_entry))
 | 
			
		||||
				< (long)offsetof(ATTR_LIST_ENTRY, name))
 | 
			
		||||
			goto corrupt;
 | 
			
		||||
		/*
 | 
			
		||||
		 * If this is an enumeration and the attribute list attribute
 | 
			
		||||
		 * is the next one in the enumeration sequence, just return the
 | 
			
		||||
| 
						 | 
				
			
			@ -3090,11 +3160,18 @@ find_attr_list_attr:
 | 
			
		|||
		/* Catch the end of the attribute list. */
 | 
			
		||||
		if ((u8*)al_entry == al_end)
 | 
			
		||||
			goto not_found;
 | 
			
		||||
		if (le16_cmpz(al_entry->length))
 | 
			
		||||
			break;
 | 
			
		||||
		if ((u8*)al_entry + 6 > al_end || (u8*)al_entry +
 | 
			
		||||
				le16_to_cpu(al_entry->length) > al_end)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if ((((u8*)al_entry + offsetof(ATTR_LIST_ENTRY, name)) > al_end)
 | 
			
		||||
		    || ((u8*)al_entry + le16_to_cpu(al_entry->length) > al_end)
 | 
			
		||||
		    || (le16_to_cpu(al_entry->length) & 7)
 | 
			
		||||
		    || (le16_to_cpu(al_entry->length)
 | 
			
		||||
				< offsetof(ATTR_LIST_ENTRY, name_length))
 | 
			
		||||
		    || (al_entry->name_length
 | 
			
		||||
			&& ((u8*)al_entry + al_entry->name_offset
 | 
			
		||||
				+ al_entry->name_length * sizeof(ntfschar))
 | 
			
		||||
				> al_end))
 | 
			
		||||
			break; /* corrupt */
 | 
			
		||||
 | 
			
		||||
		next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
 | 
			
		||||
				le16_to_cpu(al_entry->length));
 | 
			
		||||
		if (!le32_eq(type, AT_UNUSED)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3174,6 +3251,12 @@ is_enumeration:
 | 
			
		|||
				ctx->mrec = ctx->base_mrec;
 | 
			
		||||
			} else {
 | 
			
		||||
				/* We want an extent record. */
 | 
			
		||||
				if (!vol->mft_na) {
 | 
			
		||||
					ntfs_log_perror("$MFT not ready for "
 | 
			
		||||
					    "opening an extent to inode %lld\n",
 | 
			
		||||
					    (long long)base_ni->mft_no);
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
				ni = ntfs_extent_inode_open(base_ni,
 | 
			
		||||
						al_entry->mft_reference);
 | 
			
		||||
				if (!ni)
 | 
			
		||||
| 
						 | 
				
			
			@ -3202,12 +3285,18 @@ is_enumeration:
 | 
			
		|||
		 * with the same meanings as above.
 | 
			
		||||
		 */
 | 
			
		||||
do_next_attr_loop:
 | 
			
		||||
		if ((char*)a < (char*)ctx->mrec || (char*)a > (char*)ctx->mrec +
 | 
			
		||||
				le32_to_cpu(ctx->mrec->bytes_allocated))
 | 
			
		||||
		/*
 | 
			
		||||
		 * Make sure the attribute fully lies within the MFT record
 | 
			
		||||
		 * and we can safely access its minimal fields.
 | 
			
		||||
		 */
 | 
			
		||||
		offs = p2n(a) - p2n(ctx->mrec);
 | 
			
		||||
		space = le32_to_cpu(ctx->mrec->bytes_in_use) - offs;
 | 
			
		||||
		if (offs < 0)
 | 
			
		||||
			break;
 | 
			
		||||
		if (le32_eq(a->type, AT_END))
 | 
			
		||||
		if ((space >= 4) && le32_eq(a->type, AT_END))
 | 
			
		||||
			continue;
 | 
			
		||||
		if (le32_cmpz(a->length))
 | 
			
		||||
		if ((space < (ptrdiff_t)offsetof(ATTR_RECORD, resident_end))
 | 
			
		||||
		    || (space < (ptrdiff_t)le32_to_cpu(a->length)))
 | 
			
		||||
			break;
 | 
			
		||||
		if (!le16_eq(al_entry->instance, a->instance))
 | 
			
		||||
			goto do_next_attr;
 | 
			
		||||
| 
						 | 
				
			
			@ -3241,13 +3330,15 @@ do_next_attr:
 | 
			
		|||
		a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
 | 
			
		||||
		goto do_next_attr_loop;
 | 
			
		||||
	}
 | 
			
		||||
corrupt :
 | 
			
		||||
	if (ni != base_ni) {
 | 
			
		||||
		ctx->ntfs_ino = base_ni;
 | 
			
		||||
		ctx->mrec = ctx->base_mrec;
 | 
			
		||||
		ctx->attr = ctx->base_attr;
 | 
			
		||||
	}
 | 
			
		||||
	errno = EIO;
 | 
			
		||||
	ntfs_log_perror("Inode is corrupt (%lld)", (long long)base_ni->mft_no);
 | 
			
		||||
	ntfs_log_error("Corrupt attribute list entry in MFT record %lld\n",
 | 
			
		||||
			(long long)base_ni->mft_no);
 | 
			
		||||
	return -1;
 | 
			
		||||
not_found:
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -3299,6 +3390,190 @@ not_found:
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *		Check the consistency of an attribute
 | 
			
		||||
 *
 | 
			
		||||
 *	Do the general consistency checks of the selected attribute :
 | 
			
		||||
 *	- the required fields can be accessed
 | 
			
		||||
 *	- the variable fields do not overflow
 | 
			
		||||
 *	- the attribute is [non-]resident if it must be
 | 
			
		||||
 *	- miscelleaneous checks
 | 
			
		||||
 *
 | 
			
		||||
 *	Returns 0 if the checks pass
 | 
			
		||||
 *		-1 with errno = EIO otherwise
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int ntfs_attr_inconsistent(const ATTR_RECORD *a, const MFT_REF mref)
 | 
			
		||||
{
 | 
			
		||||
	const FILE_NAME_ATTR *fn;
 | 
			
		||||
	const INDEX_ROOT *ir;
 | 
			
		||||
	u64 inum;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The attribute was found to fully lie within the MFT
 | 
			
		||||
	 * record, now make sure its relevant parts (name, runlist,
 | 
			
		||||
	 * value) also lie within. The first step is to make sure
 | 
			
		||||
	 * the attribute has the minimum length so that accesses to
 | 
			
		||||
	 * the lengths and offsets of these parts are safe.
 | 
			
		||||
	 */
 | 
			
		||||
	ret = 0;
 | 
			
		||||
	inum = MREF(mref);
 | 
			
		||||
	if (a->non_resident) {
 | 
			
		||||
		if ((a->non_resident != 1)
 | 
			
		||||
		    || (le32_to_cpu(a->length)
 | 
			
		||||
			< offsetof(ATTR_RECORD, non_resident_end))
 | 
			
		||||
		    || (le16_to_cpu(a->mapping_pairs_offset)
 | 
			
		||||
				>= le32_to_cpu(a->length))
 | 
			
		||||
		    || (a->name_length
 | 
			
		||||
			 && (((u32)le16_to_cpu(a->name_offset)
 | 
			
		||||
				+ a->name_length * sizeof(ntfschar))
 | 
			
		||||
				> le32_to_cpu(a->length)))
 | 
			
		||||
		    || (le64_to_cpu(a->highest_vcn)
 | 
			
		||||
				< le64_to_cpu(a->lowest_vcn))) {
 | 
			
		||||
			ntfs_log_error("Corrupt non resident attribute"
 | 
			
		||||
				" 0x%x in MFT record %lld\n",
 | 
			
		||||
				(int)le32_to_cpu(a->type),
 | 
			
		||||
				(long long)inum);
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			ret = -1;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if ((le32_to_cpu(a->length)
 | 
			
		||||
			< offsetof(ATTR_RECORD, resident_end))
 | 
			
		||||
		    || (le32_to_cpu(a->value_length) & 0xff000000)
 | 
			
		||||
		    || (!le32_cmpz(a->value_length)
 | 
			
		||||
			&& ((le16_to_cpu(a->value_offset)
 | 
			
		||||
				+ le32_to_cpu(a->value_length))
 | 
			
		||||
				> le32_to_cpu(a->length)))
 | 
			
		||||
		    || (a->name_length
 | 
			
		||||
			&& (((u32)le16_to_cpu(a->name_offset)
 | 
			
		||||
				+ a->name_length * sizeof(ntfschar))
 | 
			
		||||
				> le32_to_cpu(a->length)))) {
 | 
			
		||||
			ntfs_log_error("Corrupt resident attribute"
 | 
			
		||||
				" 0x%x in MFT record %lld\n",
 | 
			
		||||
				(int)le32_to_cpu(a->type),
 | 
			
		||||
				(long long)inum);
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			ret = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Checking whether an attribute must be [non-]resident
 | 
			
		||||
		 * is hard-coded for well-known ones. This should be
 | 
			
		||||
		 * done through ntfs_attr_can_be_non_resident(), based on
 | 
			
		||||
		 * $AttrDef, but this would give an easy way to bypass
 | 
			
		||||
		 * the checks.
 | 
			
		||||
		 * Attributes which are not well-known are not checked.
 | 
			
		||||
		 *
 | 
			
		||||
		 * Note : at this stage we know that a->length and
 | 
			
		||||
		 * a->value_length cannot look like being negative.
 | 
			
		||||
		 */
 | 
			
		||||
		/* switch(a->type) { */
 | 
			
		||||
		if (le32_eq(a->type, AT_FILE_NAME)) {
 | 
			
		||||
			/* Check file names are resident and do not overflow */
 | 
			
		||||
			fn = (const FILE_NAME_ATTR*)((const u8*)a
 | 
			
		||||
				+ le16_to_cpu(a->value_offset));
 | 
			
		||||
			if (a->non_resident
 | 
			
		||||
			    || (le32_to_cpu(a->value_length)
 | 
			
		||||
				< offsetof(FILE_NAME_ATTR, file_name))
 | 
			
		||||
			    || !fn->file_name_length
 | 
			
		||||
			    || ((fn->file_name_length * sizeof(ntfschar)
 | 
			
		||||
				+ offsetof(FILE_NAME_ATTR, file_name))
 | 
			
		||||
				> le32_to_cpu(a->value_length))) {
 | 
			
		||||
				ntfs_log_error("Corrupt file name"
 | 
			
		||||
					" attribute in MFT record %lld.\n",
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (le32_eq(a->type, AT_INDEX_ROOT)) {
 | 
			
		||||
			/* Check root index is resident and does not overflow */
 | 
			
		||||
			ir = (const INDEX_ROOT*)((const u8*)a +
 | 
			
		||||
				le16_to_cpu(a->value_offset));
 | 
			
		||||
			/* index.allocated_size may overflow while resizing */
 | 
			
		||||
			if (a->non_resident
 | 
			
		||||
			    || (le32_to_cpu(a->value_length)
 | 
			
		||||
				< offsetof(INDEX_ROOT, index.reserved))
 | 
			
		||||
			    || (le32_to_cpu(ir->index.entries_offset)
 | 
			
		||||
				< sizeof(INDEX_HEADER))
 | 
			
		||||
			    || (le32_to_cpu(ir->index.index_length)
 | 
			
		||||
				< le32_to_cpu(ir->index.entries_offset))
 | 
			
		||||
			    || (le32_to_cpu(ir->index.allocated_size)
 | 
			
		||||
				< le32_to_cpu(ir->index.index_length))
 | 
			
		||||
			    || (le32_to_cpu(a->value_length)
 | 
			
		||||
				< (le32_to_cpu(ir->index.allocated_size)
 | 
			
		||||
				    + offsetof(INDEX_ROOT, reserved)))) {
 | 
			
		||||
				ntfs_log_error("Corrupt index root"
 | 
			
		||||
					" in MFT record %lld.\n",
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (le32_eq(a->type, AT_STANDARD_INFORMATION)) {
 | 
			
		||||
			if (a->non_resident
 | 
			
		||||
			    || (le32_to_cpu(a->value_length)
 | 
			
		||||
					< offsetof(STANDARD_INFORMATION,
 | 
			
		||||
							v1_end))) {
 | 
			
		||||
				ntfs_log_error("Corrupt standard information"
 | 
			
		||||
					" in MFT record %lld\n",
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (le32_eq(a->type, AT_OBJECT_ID)) {
 | 
			
		||||
			if (a->non_resident
 | 
			
		||||
			    || (le32_to_cpu(a->value_length)
 | 
			
		||||
					< sizeof(GUID))) {
 | 
			
		||||
				ntfs_log_error("Corrupt object id"
 | 
			
		||||
					" in MFT record %lld\n",
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (le32_eq(a->type, AT_VOLUME_NAME) ||
 | 
			
		||||
			le32_eq(a->type, AT_EA_INFORMATION)) {
 | 
			
		||||
			if (a->non_resident) {
 | 
			
		||||
				ntfs_log_error("Attribute 0x%x in MFT record"
 | 
			
		||||
					" %lld should be resident.\n",
 | 
			
		||||
					(int)le32_to_cpu(a->type),
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (le32_eq(a->type, AT_VOLUME_INFORMATION)) {
 | 
			
		||||
			if (a->non_resident
 | 
			
		||||
			    || (le32_to_cpu(a->value_length)
 | 
			
		||||
					< sizeof(VOLUME_INFORMATION))) {
 | 
			
		||||
				ntfs_log_error("Corrupt volume information"
 | 
			
		||||
					" in MFT record %lld\n",
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (le32_eq(a->type, AT_INDEX_ALLOCATION)) {
 | 
			
		||||
			if (!a->non_resident) {
 | 
			
		||||
				ntfs_log_error("Corrupt index allocation"
 | 
			
		||||
					" in MFT record %lld",
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				errno = EIO;
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
		}
 | 
			
		||||
		/* } */
 | 
			
		||||
	}
 | 
			
		||||
	return (ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ntfs_attr_lookup - find an attribute in an ntfs inode
 | 
			
		||||
 * @type:	attribute type to find
 | 
			
		||||
| 
						 | 
				
			
			@ -3546,8 +3821,9 @@ ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
 | 
			
		|||
		ntfs_log_perror("%s: type=%d", __FUNCTION__, le32_to_cpu(type));
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef <
 | 
			
		||||
			vol->attrdef_len && !le32_cmpz(ad->type); ++ad) {
 | 
			
		||||
	for (ad = vol->attrdef; ((ptrdiff_t)((u8*)ad - (u8*)vol->attrdef
 | 
			
		||||
				+ sizeof(ATTR_DEF)) <= vol->attrdef_len)
 | 
			
		||||
			&& !le32_cmpz(ad->type); ++ad) {
 | 
			
		||||
		/* We haven't found it yet, carry on searching. */
 | 
			
		||||
		if (le32_to_cpu(ad->type) < le32_to_cpu(type))
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -4533,6 +4809,13 @@ int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
 | 
			
		|||
		}
 | 
			
		||||
		
 | 
			
		||||
		/* Move attributes following @a to their new location. */
 | 
			
		||||
		if (((u8 *)m + old_size) < ((u8 *)a + attr_size)) {
 | 
			
		||||
			ntfs_log_error("Attribute 0x%x overflows"
 | 
			
		||||
				" from MFT record\n",
 | 
			
		||||
				(int)le32_to_cpu(a->type));
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			return (-1);
 | 
			
		||||
		}
 | 
			
		||||
		memmove((u8 *)a + new_size, (u8 *)a + attr_size,
 | 
			
		||||
			old_size - ((u8 *)a - (u8 *)m) - attr_size);
 | 
			
		||||
		
 | 
			
		||||
| 
						 | 
				
			
			@ -4567,6 +4850,13 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
 | 
			
		|||
	
 | 
			
		||||
	ntfs_log_trace("Entering for new size %u.\n", (unsigned)new_size);
 | 
			
		||||
 | 
			
		||||
	if (le32_cmpz(a->value_length)) {
 | 
			
		||||
			/* Offset is unsafe when no value */
 | 
			
		||||
		int offset = ((offsetof(ATTR_RECORD, resident_end)
 | 
			
		||||
			+ a->name_length*sizeof(ntfschar) - 1) | 7) + 1;
 | 
			
		||||
		a->value_offset = cpu_to_le16(offset);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Resize the resident part of the attribute record. */
 | 
			
		||||
	if ((ret = ntfs_attr_record_resize(m, a, (le16_to_cpu(a->value_offset) +
 | 
			
		||||
			new_size + 7) & ~7)) < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -6663,6 +6953,20 @@ void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
 | 
			
		|||
		ntfs_log_perror("ntfs_attr_open failed, inode %lld attr 0x%lx",
 | 
			
		||||
				(long long)ni->mft_no,(long)le32_to_cpu(type));
 | 
			
		||||
		goto err_exit;
 | 
			
		||||
	}
 | 
			
		||||
		/*
 | 
			
		||||
		 * Consistency check : restrict to 65536 bytes.
 | 
			
		||||
		 *   index bitmaps may need more, but still limited by
 | 
			
		||||
		 *   the number of clusters.
 | 
			
		||||
		 */
 | 
			
		||||
	if (((u64)na->data_size > 65536)
 | 
			
		||||
	    && (!le32_eq(type, AT_BITMAP)
 | 
			
		||||
		|| ((u64)na->data_size > 
 | 
			
		||||
			(u64)((ni->vol->nr_clusters + 7) >> 3)))) {
 | 
			
		||||
		ntfs_log_error("Corrupt attribute 0x%lx in inode %lld\n",
 | 
			
		||||
				(long)le32_to_cpu(type),(long long)ni->mft_no);
 | 
			
		||||
		errno = EOVERFLOW;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	data = ntfs_malloc(na->data_size);
 | 
			
		||||
	if (!data)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,7 +155,9 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/* MFT and MFTMirr may not overlap the boot sector or be the same */
 | 
			
		||||
	if (sle64_cmpz(b->mft_lcn) || sle64_cmpz(b->mftmirr_lcn) || sle64_eq(b->mft_lcn, b->mftmirr_lcn)) {
 | 
			
		||||
	if (((s64)sle64_to_cpu(b->mft_lcn) <= 0)
 | 
			
		||||
	    || ((s64)sle64_to_cpu(b->mftmirr_lcn) <= 0)
 | 
			
		||||
	    || sle64_eq(b->mft_lcn, b->mftmirr_lcn)) {
 | 
			
		||||
		ntfs_log_error("Invalid location of MFT or MFTMirr.\n");
 | 
			
		||||
		goto not_ntfs;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -752,6 +752,12 @@ s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b)
 | 
			
		|||
	/* If it is a resident attribute, simply use ntfs_attr_pread(). */
 | 
			
		||||
	if (!NAttrNonResident(na))
 | 
			
		||||
		return ntfs_attr_pread(na, pos, count, b);
 | 
			
		||||
	if (na->compression_block_size < NTFS_SB_SIZE) {
 | 
			
		||||
		ntfs_log_error("Unsupported compression block size %ld\n",
 | 
			
		||||
				(long)na->compression_block_size);
 | 
			
		||||
		errno = EOVERFLOW;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
	total = total2 = 0;
 | 
			
		||||
	/* Zero out reads beyond initialized size. */
 | 
			
		||||
	if (pos + count > na->initialized_size) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1618,7 +1624,7 @@ static int ntfs_read_append(ntfs_attr *na, const runlist_element *rl,
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
static s32 ntfs_flush(ntfs_attr *na, runlist_element *rl, s64 offs,
 | 
			
		||||
			const char *outbuf, s32 count, BOOL compress,
 | 
			
		||||
			char *outbuf, s32 count, BOOL compress,
 | 
			
		||||
			BOOL appending, VCN *update_from)
 | 
			
		||||
{
 | 
			
		||||
	s32 rounded;
 | 
			
		||||
| 
						 | 
				
			
			@ -1639,6 +1645,8 @@ static s32 ntfs_flush(ntfs_attr *na, runlist_element *rl, s64 offs,
 | 
			
		|||
	if (!compress) {
 | 
			
		||||
		clsz = 1 << na->ni->vol->cluster_size_bits;
 | 
			
		||||
		rounded = ((count - 1) | (clsz - 1)) + 1;
 | 
			
		||||
		if (rounded > count)
 | 
			
		||||
			memset(&outbuf[count], 0, rounded - count);
 | 
			
		||||
		written = write_clusters(na->ni->vol, rl,
 | 
			
		||||
				offs, rounded, outbuf);
 | 
			
		||||
		if (written != rounded)
 | 
			
		||||
| 
						 | 
				
			
			@ -1700,6 +1708,12 @@ s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *wrl, s64 wpos,
 | 
			
		|||
		errno = EIO;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
	if (na->compression_block_size < NTFS_SB_SIZE) {
 | 
			
		||||
		ntfs_log_error("Unsupported compression block size %ld\n",
 | 
			
		||||
				(long)na->compression_block_size);
 | 
			
		||||
		errno = EOVERFLOW;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
	if (wrl->vcn < *update_from)
 | 
			
		||||
		*update_from = wrl->vcn;
 | 
			
		||||
	written = -1; /* default return */
 | 
			
		||||
| 
						 | 
				
			
			@ -1881,6 +1895,12 @@ int ntfs_compressed_close(ntfs_attr *na, runlist_element *wrl, s64 offs,
 | 
			
		|||
		errno = EIO;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
	if (na->compression_block_size < NTFS_SB_SIZE) {
 | 
			
		||||
		ntfs_log_error("Unsupported compression block size %ld\n",
 | 
			
		||||
				(long)na->compression_block_size);
 | 
			
		||||
		errno = EOVERFLOW;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
	if (wrl->vcn < *update_from)
 | 
			
		||||
		*update_from = wrl->vcn;
 | 
			
		||||
	vol = na->ni->vol;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										109
									
								
								libntfs-3g/dir.c
								
								
								
								
							
							
						
						
									
										109
									
								
								libntfs-3g/dir.c
								
								
								
								
							| 
						 | 
				
			
			@ -293,6 +293,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
 | 
			
		|||
				(unsigned)index_block_size);
 | 
			
		||||
		goto put_err_out;
 | 
			
		||||
	}
 | 
			
		||||
		/* Consistency check of ir done while fetching attribute */
 | 
			
		||||
	index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
 | 
			
		||||
	/* The first index entry. */
 | 
			
		||||
	ie = (INDEX_ENTRY*)((u8*)&ir->index +
 | 
			
		||||
| 
						 | 
				
			
			@ -305,10 +306,11 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
 | 
			
		|||
		/* Bounds checks. */
 | 
			
		||||
		if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
 | 
			
		||||
				sizeof(INDEX_ENTRY_HEADER) > index_end ||
 | 
			
		||||
				(u8*)ie + le16_to_cpu(ie->key_length) >
 | 
			
		||||
				(u8*)ie + le16_to_cpu(ie->length) >
 | 
			
		||||
				index_end) {
 | 
			
		||||
			ntfs_log_error("Index entry out of bounds in inode %lld"
 | 
			
		||||
				       "\n", (unsigned long long)dir_ni->mft_no);
 | 
			
		||||
			ntfs_log_error("Index root entry out of bounds in"
 | 
			
		||||
				" inode %lld\n",
 | 
			
		||||
				(unsigned long long)dir_ni->mft_no);
 | 
			
		||||
			goto put_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		/*
 | 
			
		||||
| 
						 | 
				
			
			@ -318,9 +320,10 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
 | 
			
		|||
		if (!le16_andz(ie->ie_flags, INDEX_ENTRY_END))
 | 
			
		||||
			break;
 | 
			
		||||
		
 | 
			
		||||
		if (!le16_to_cpu(ie->length)) {
 | 
			
		||||
			ntfs_log_error("Zero length index entry in inode %lld"
 | 
			
		||||
				       "\n", (unsigned long long)dir_ni->mft_no);
 | 
			
		||||
		/* The file name must not overflow from the entry */
 | 
			
		||||
		if (ntfs_index_entry_inconsistent(ie, COLLATION_FILE_NAME,
 | 
			
		||||
				dir_ni->mft_no)) {
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			goto put_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		/*
 | 
			
		||||
| 
						 | 
				
			
			@ -398,37 +401,18 @@ descend_into_child_node:
 | 
			
		|||
	if (br != 1) {
 | 
			
		||||
		if (br != -1)
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
		ntfs_log_perror("Failed to read vcn 0x%llx",
 | 
			
		||||
			       	(unsigned long long)vcn);
 | 
			
		||||
		ntfs_log_perror("Failed to read vcn 0x%llx from inode %lld",
 | 
			
		||||
			       	(unsigned long long)vcn,
 | 
			
		||||
				(unsigned long long)ia_na->ni->mft_no);
 | 
			
		||||
		goto close_err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
 | 
			
		||||
		ntfs_log_error("Actual VCN (0x%llx) of index buffer is different "
 | 
			
		||||
				"from expected VCN (0x%llx).\n",
 | 
			
		||||
				(long long)sle64_to_cpu(ia->index_block_vcn),
 | 
			
		||||
				(long long)vcn);
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		goto close_err_out;
 | 
			
		||||
	}
 | 
			
		||||
	if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) {
 | 
			
		||||
		ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode 0x%llx "
 | 
			
		||||
				"has a size (%u) differing from the directory "
 | 
			
		||||
				"specified size (%u).\n", (long long)vcn,
 | 
			
		||||
				(unsigned long long)dir_ni->mft_no,
 | 
			
		||||
				(unsigned) le32_to_cpu(ia->index.allocated_size) + 0x18,
 | 
			
		||||
				(unsigned)index_block_size);
 | 
			
		||||
	if (ntfs_index_block_inconsistent((INDEX_BLOCK*)ia, index_block_size,
 | 
			
		||||
			ia_na->ni->mft_no, vcn)) {
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		goto close_err_out;
 | 
			
		||||
	}
 | 
			
		||||
	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
 | 
			
		||||
	if (index_end > (u8*)ia + index_block_size) {
 | 
			
		||||
		ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode "
 | 
			
		||||
				"0x%llx exceeds maximum size.\n",
 | 
			
		||||
				(long long)vcn, (unsigned long long)dir_ni->mft_no);
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		goto close_err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* The first index entry. */
 | 
			
		||||
	ie = (INDEX_ENTRY*)((u8*)&ia->index +
 | 
			
		||||
| 
						 | 
				
			
			@ -442,7 +426,7 @@ descend_into_child_node:
 | 
			
		|||
		/* Bounds check. */
 | 
			
		||||
		if ((u8*)ie < (u8*)ia || (u8*)ie +
 | 
			
		||||
				sizeof(INDEX_ENTRY_HEADER) > index_end ||
 | 
			
		||||
				(u8*)ie + le16_to_cpu(ie->key_length) >
 | 
			
		||||
				(u8*)ie + le16_to_cpu(ie->length) >
 | 
			
		||||
				index_end) {
 | 
			
		||||
			ntfs_log_error("Index entry out of bounds in directory "
 | 
			
		||||
				       "inode %lld.\n", 
 | 
			
		||||
| 
						 | 
				
			
			@ -457,10 +441,10 @@ descend_into_child_node:
 | 
			
		|||
		if (!le16_andz(ie->ie_flags, INDEX_ENTRY_END))
 | 
			
		||||
			break;
 | 
			
		||||
		
 | 
			
		||||
		if (!le16_to_cpu(ie->length)) {
 | 
			
		||||
		/* The file name must not overflow from the entry */
 | 
			
		||||
		if (ntfs_index_entry_inconsistent(ie, COLLATION_FILE_NAME,
 | 
			
		||||
				dir_ni->mft_no)) {
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			ntfs_log_error("Zero length index entry in inode %lld"
 | 
			
		||||
				       "\n", (unsigned long long)dir_ni->mft_no);
 | 
			
		||||
			goto close_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		/*
 | 
			
		||||
| 
						 | 
				
			
			@ -1086,12 +1070,6 @@ static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
 | 
			
		|||
	}
 | 
			
		||||
	fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
 | 
			
		||||
			le16_to_cpu(ctx->attr->value_offset));
 | 
			
		||||
	if ((u8*)fn +	le32_to_cpu(ctx->attr->value_length) >
 | 
			
		||||
			(u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) {
 | 
			
		||||
		ntfs_log_error("Corrupt file name attribute in inode %lld.\n",
 | 
			
		||||
			       (unsigned long long)ni->mft_no);
 | 
			
		||||
		goto io_err_out;
 | 
			
		||||
	}
 | 
			
		||||
	mref = le64_to_cpu(fn->parent_directory);
 | 
			
		||||
	ntfs_attr_put_search_ctx(ctx);
 | 
			
		||||
	return mref;
 | 
			
		||||
| 
						 | 
				
			
			@ -1250,9 +1228,13 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
 | 
			
		|||
		/* Bounds checks. */
 | 
			
		||||
		if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
 | 
			
		||||
				sizeof(INDEX_ENTRY_HEADER) > index_end ||
 | 
			
		||||
				(u8*)ie + le16_to_cpu(ie->key_length) >
 | 
			
		||||
				index_end)
 | 
			
		||||
				(u8*)ie + le16_to_cpu(ie->length) >
 | 
			
		||||
				index_end) {
 | 
			
		||||
			ntfs_log_error("Index root entry out of bounds in"
 | 
			
		||||
					" inode %lld\n",
 | 
			
		||||
					(unsigned long long)dir_ni->mft_no);
 | 
			
		||||
			goto dir_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		/* The last entry cannot contain a name. */
 | 
			
		||||
		if (!le16_andz(ie->ie_flags, INDEX_ENTRY_END))
 | 
			
		||||
			break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1263,6 +1245,13 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
 | 
			
		|||
		/* Skip index root entry if continuing previous readdir. */
 | 
			
		||||
		if (ir_pos > (u8*)ie - (u8*)ir)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* The file name must not overflow from the entry */
 | 
			
		||||
		if (ntfs_index_entry_inconsistent(ie, COLLATION_FILE_NAME,
 | 
			
		||||
				dir_ni->mft_no)) {
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			goto dir_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		/*
 | 
			
		||||
		 * Submit the directory entry to ntfs_filldir(), which will
 | 
			
		||||
		 * invoke the filldir() callback as appropriate.
 | 
			
		||||
| 
						 | 
				
			
			@ -1362,33 +1351,12 @@ find_next_index_buffer:
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	ia_start = ia_pos & ~(s64)(index_block_size - 1);
 | 
			
		||||
	if (sle64_to_cpu(ia->index_block_vcn) != ia_start >>
 | 
			
		||||
			index_vcn_size_bits) {
 | 
			
		||||
		ntfs_log_error("Actual VCN (0x%llx) of index buffer is different "
 | 
			
		||||
				"from expected VCN (0x%llx) in inode 0x%llx.\n",
 | 
			
		||||
				(long long)sle64_to_cpu(ia->index_block_vcn),
 | 
			
		||||
				(long long)ia_start >> index_vcn_size_bits,
 | 
			
		||||
				(unsigned long long)dir_ni->mft_no);
 | 
			
		||||
		goto dir_err_out;
 | 
			
		||||
	}
 | 
			
		||||
	if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) {
 | 
			
		||||
		ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode %lld "
 | 
			
		||||
				"has a size (%u) differing from the directory "
 | 
			
		||||
				"specified size (%u).\n", (long long)ia_start >>
 | 
			
		||||
				index_vcn_size_bits,
 | 
			
		||||
				(unsigned long long)dir_ni->mft_no,
 | 
			
		||||
				(unsigned) le32_to_cpu(ia->index.allocated_size)
 | 
			
		||||
				+ 0x18, (unsigned)index_block_size);
 | 
			
		||||
	if (ntfs_index_block_inconsistent((INDEX_BLOCK*)ia, index_block_size,
 | 
			
		||||
			ia_na->ni->mft_no, ia_start >> index_vcn_size_bits)) {
 | 
			
		||||
		goto dir_err_out;
 | 
			
		||||
	}
 | 
			
		||||
	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
 | 
			
		||||
	if (index_end > (u8*)ia + index_block_size) {
 | 
			
		||||
		ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode "
 | 
			
		||||
				"%lld exceeds maximum size.\n",
 | 
			
		||||
				(long long)ia_start >> index_vcn_size_bits,
 | 
			
		||||
				(unsigned long long)dir_ni->mft_no);
 | 
			
		||||
		goto dir_err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* The first index entry. */
 | 
			
		||||
	ie = (INDEX_ENTRY*)((u8*)&ia->index +
 | 
			
		||||
			le32_to_cpu(ia->index.entries_offset));
 | 
			
		||||
| 
						 | 
				
			
			@ -1403,7 +1371,7 @@ find_next_index_buffer:
 | 
			
		|||
		/* Bounds checks. */
 | 
			
		||||
		if ((u8*)ie < (u8*)ia || (u8*)ie +
 | 
			
		||||
				sizeof(INDEX_ENTRY_HEADER) > index_end ||
 | 
			
		||||
				(u8*)ie + le16_to_cpu(ie->key_length) >
 | 
			
		||||
				(u8*)ie + le16_to_cpu(ie->length) >
 | 
			
		||||
				index_end) {
 | 
			
		||||
			ntfs_log_error("Index entry out of bounds in directory inode "
 | 
			
		||||
				"%lld.\n", (unsigned long long)dir_ni->mft_no);
 | 
			
		||||
| 
						 | 
				
			
			@ -1419,6 +1387,13 @@ find_next_index_buffer:
 | 
			
		|||
		/* Skip index entry if continuing previous readdir. */
 | 
			
		||||
		if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* The file name must not overflow from the entry */
 | 
			
		||||
		if (ntfs_index_entry_inconsistent(ie, COLLATION_FILE_NAME,
 | 
			
		||||
				dir_ni->mft_no)) {
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			goto dir_err_out;
 | 
			
		||||
		}
 | 
			
		||||
		/*
 | 
			
		||||
		 * Submit the directory entry to ntfs_filldir(), which will
 | 
			
		||||
		 * invoke the filldir() callback as appropriate.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
 * Copyright (c) 2004-2005 Richard Russon
 | 
			
		||||
 * Copyright (c) 2005-2006 Yura Pakhuchiy
 | 
			
		||||
 * Copyright (c) 2005-2008 Szabolcs Szakacsits
 | 
			
		||||
 * Copyright (c) 2007-2020 Jean-Pierre Andre
 | 
			
		||||
 * Copyright (c) 2007-2021 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
 | 
			
		||||
| 
						 | 
				
			
			@ -388,42 +388,6 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie)
 | 
			
		|||
	return dup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
 | 
			
		||||
{
 | 
			
		||||
	u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18;
 | 
			
		||||
	
 | 
			
		||||
	ntfs_log_trace("Entering\n");
 | 
			
		||||
	
 | 
			
		||||
	if (!ntfs_is_indx_record(ib->magic)) {
 | 
			
		||||
		
 | 
			
		||||
		ntfs_log_error("Corrupt index block signature: vcn %lld inode "
 | 
			
		||||
			       "%llu\n", (long long)vcn,
 | 
			
		||||
			       (unsigned long long)icx->ni->mft_no);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (sle64_to_cpu(ib->index_block_vcn) != vcn) {
 | 
			
		||||
		
 | 
			
		||||
		ntfs_log_error("Corrupt index block: VCN (%lld) is different "
 | 
			
		||||
			       "from expected VCN (%lld) in inode %llu\n",
 | 
			
		||||
			       (long long)sle64_to_cpu(ib->index_block_vcn),
 | 
			
		||||
			       (long long)vcn,
 | 
			
		||||
			       (unsigned long long)icx->ni->mft_no);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (ib_size != icx->block_size) {
 | 
			
		||||
		
 | 
			
		||||
		ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu "
 | 
			
		||||
			       "has a size (%u) differing from the index "
 | 
			
		||||
			       "specified size (%u)\n", (long long)vcn, 
 | 
			
		||||
			       (unsigned long long)icx->ni->mft_no, ib_size,
 | 
			
		||||
			       icx->block_size);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
 | 
			
		||||
				  u32 name_len, ntfs_attr_search_ctx **ctx)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -469,6 +433,133 @@ static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len)
 | 
			
		|||
	return ir;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *		Check the consistency of an index block
 | 
			
		||||
 *
 | 
			
		||||
 *	Make sure the index block does not overflow from the index record.
 | 
			
		||||
 *	The size of block is assumed to have been checked to be what is
 | 
			
		||||
 *	defined in the index root.
 | 
			
		||||
 *
 | 
			
		||||
 *	Returns 0 if no error was found
 | 
			
		||||
 *		-1 otherwise (with errno unchanged)
 | 
			
		||||
 *
 | 
			
		||||
 *      |<--->|  offsetof(INDEX_BLOCK, index)
 | 
			
		||||
 *      |     |<--->|  sizeof(INDEX_HEADER)
 | 
			
		||||
 *      |     |     |
 | 
			
		||||
 *      |     |     | seq          index entries         unused
 | 
			
		||||
 *      |=====|=====|=====|===========================|==============|
 | 
			
		||||
 *      |     |           |                           |              |
 | 
			
		||||
 *      |     |<--------->| entries_offset            |              |
 | 
			
		||||
 *      |     |<---------------- index_length ------->|              |
 | 
			
		||||
 *      |     |<--------------------- allocated_size --------------->|
 | 
			
		||||
 *      |<--------------------------- block_size ------------------->|
 | 
			
		||||
 *
 | 
			
		||||
 *      size(INDEX_HEADER) <= ent_offset < ind_length <= alloc_size < bk_size
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int ntfs_index_block_inconsistent(const INDEX_BLOCK *ib, u32 block_size,
 | 
			
		||||
			u64 inum, VCN vcn)
 | 
			
		||||
{
 | 
			
		||||
	u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size)
 | 
			
		||||
			+ offsetof(INDEX_BLOCK, index);
 | 
			
		||||
 | 
			
		||||
	if (!ntfs_is_indx_record(ib->magic)) {
 | 
			
		||||
		ntfs_log_error("Corrupt index block signature: vcn %lld inode "
 | 
			
		||||
			       "%llu\n", (long long)vcn,
 | 
			
		||||
			       (unsigned long long)inum);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (sle64_to_cpu(ib->index_block_vcn) != vcn) {
 | 
			
		||||
		ntfs_log_error("Corrupt index block: VCN (%lld) is different "
 | 
			
		||||
			       "from expected VCN (%lld) in inode %llu\n",
 | 
			
		||||
			       (long long)sle64_to_cpu(ib->index_block_vcn),
 | 
			
		||||
			       (long long)vcn,
 | 
			
		||||
			       (unsigned long long)inum);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (ib_size != block_size) {
 | 
			
		||||
		ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu "
 | 
			
		||||
			       "has a size (%u) differing from the index "
 | 
			
		||||
			       "specified size (%u)\n", (long long)vcn, 
 | 
			
		||||
			       (unsigned long long)inum, ib_size,
 | 
			
		||||
			       (unsigned int)block_size);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (le32_to_cpu(ib->index.entries_offset) < sizeof(INDEX_HEADER)) {
 | 
			
		||||
		ntfs_log_error("Invalid index entry offset in inode %lld\n",
 | 
			
		||||
				(unsigned long long)inum);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (le32_to_cpu(ib->index.index_length)
 | 
			
		||||
			<= le32_to_cpu(ib->index.entries_offset)) {
 | 
			
		||||
		ntfs_log_error("No space for index entries in inode %lld\n",
 | 
			
		||||
				(unsigned long long)inum);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (le32_to_cpu(ib->index.allocated_size)
 | 
			
		||||
			< le32_to_cpu(ib->index.index_length)) {
 | 
			
		||||
		ntfs_log_error("Index entries overflow in inode %lld\n",
 | 
			
		||||
				(unsigned long long)inum);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *		Check the consistency of an index entry
 | 
			
		||||
 *
 | 
			
		||||
 *	Make sure data and key do not overflow from entry.
 | 
			
		||||
 *	As a side effect, an entry with zero length is rejected.
 | 
			
		||||
 *	This entry must be a full one (no INDEX_ENTRY_END flag), and its
 | 
			
		||||
 *	length must have been checked beforehand to not overflow from the
 | 
			
		||||
 *	index record.
 | 
			
		||||
 *
 | 
			
		||||
 *	Returns 0 if no error was found
 | 
			
		||||
 *		-1 otherwise (with errno unchanged)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int ntfs_index_entry_inconsistent(const INDEX_ENTRY *ie,
 | 
			
		||||
			COLLATION_RULES collation_rule, u64 inum)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = 0;
 | 
			
		||||
	if (!le16_cmpz(ie->key_length)
 | 
			
		||||
		&& ((le16_to_cpu(ie->key_length) + offsetof(INDEX_ENTRY, key))
 | 
			
		||||
			    > le16_to_cpu(ie->length))) {
 | 
			
		||||
		ntfs_log_error("Overflow from index entry in inode %lld\n",
 | 
			
		||||
				(long long)inum);
 | 
			
		||||
		ret = -1;
 | 
			
		||||
 | 
			
		||||
	} else
 | 
			
		||||
		if (le32_eq(collation_rule, COLLATION_FILE_NAME)) {
 | 
			
		||||
			if ((offsetof(INDEX_ENTRY, key.file_name.file_name)
 | 
			
		||||
				    + ie->key.file_name.file_name_length
 | 
			
		||||
						* sizeof(ntfschar))
 | 
			
		||||
				> le16_to_cpu(ie->length)) {
 | 
			
		||||
				ntfs_log_error("File name overflow from index"
 | 
			
		||||
					" entry in inode %lld\n",
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if (!le16_cmpz(ie->data_length)
 | 
			
		||||
				&& ((le16_to_cpu(ie->data_offset)
 | 
			
		||||
				    + le16_to_cpu(ie->data_length))
 | 
			
		||||
				    > le16_to_cpu(ie->length))) {
 | 
			
		||||
				ntfs_log_error("Data overflow from index"
 | 
			
		||||
					" entry in inode %lld\n",
 | 
			
		||||
					(long long)inum);
 | 
			
		||||
				ret = -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	return (ret);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 
 | 
			
		||||
 * Find a key in the index block.
 | 
			
		||||
 * 
 | 
			
		||||
| 
						 | 
				
			
			@ -521,6 +612,12 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
 | 
			
		|||
			ntfs_log_error("Collation function not defined\n");
 | 
			
		||||
			errno = EOPNOTSUPP;
 | 
			
		||||
			return STATUS_ERROR;
 | 
			
		||||
		}
 | 
			
		||||
			/* Make sure key and data do not overflow from entry */
 | 
			
		||||
		if (ntfs_index_entry_inconsistent(ie, icx->ir->collation_rule,
 | 
			
		||||
				icx->ni->mft_no)) {
 | 
			
		||||
			errno = EIO;
 | 
			
		||||
			return STATUS_ERROR;
 | 
			
		||||
		}
 | 
			
		||||
		rc = icx->collate(icx->ni->vol, key, key_len,
 | 
			
		||||
					&ie->key, le16_to_cpu(ie->key_length));
 | 
			
		||||
| 
						 | 
				
			
			@ -606,8 +703,11 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
 | 
			
		|||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (ntfs_ia_check(icx, dst, vcn))
 | 
			
		||||
	if (ntfs_index_block_inconsistent((INDEX_BLOCK*)dst, icx->block_size,
 | 
			
		||||
				icx->ia_na->ni->mft_no, vcn)) {
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -703,6 +803,7 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
 | 
			
		|||
	else
 | 
			
		||||
		icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
 | 
			
		||||
			/* get the appropriate collation function */
 | 
			
		||||
	icx->ir = ir;
 | 
			
		||||
	icx->collate = ntfs_get_collate_function(ir->collation_rule);
 | 
			
		||||
	if (!icx->collate) {
 | 
			
		||||
		err = errno = EOPNOTSUPP;
 | 
			
		||||
| 
						 | 
				
			
			@ -712,10 +813,6 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
 | 
			
		|||
	}
 | 
			
		||||
	
 | 
			
		||||
	old_vcn = VCN_INDEX_ROOT_PARENT;
 | 
			
		||||
	/* 
 | 
			
		||||
	 * FIXME: check for both ir and ib that the first index entry is
 | 
			
		||||
	 * within the index block.
 | 
			
		||||
	 */
 | 
			
		||||
	ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie);
 | 
			
		||||
	if (ret == STATUS_ERROR) {
 | 
			
		||||
		err = errno;
 | 
			
		||||
| 
						 | 
				
			
			@ -782,6 +879,10 @@ descend_into_child_node:
 | 
			
		|||
err_out:
 | 
			
		||||
	icx->bad_index = TRUE;	/* Force icx->* to be freed */
 | 
			
		||||
err_lookup:
 | 
			
		||||
	if (icx->actx) {
 | 
			
		||||
		ntfs_attr_put_search_ctx(icx->actx);
 | 
			
		||||
		icx->actx = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	free(ib);
 | 
			
		||||
	if (!err)
 | 
			
		||||
		err = EIO;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -189,6 +189,13 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
 | 
			
		|||
					" %lld", (long long)MREF(mref));
 | 
			
		||||
		goto put_err_out;
 | 
			
		||||
	}
 | 
			
		||||
	lthle = ctx->attr->value_length;
 | 
			
		||||
	if (le32_to_cpu(lthle) < offsetof(STANDARD_INFORMATION, owner_id)) {
 | 
			
		||||
		ntfs_log_error("Corrupt STANDARD_INFORMATION in base"
 | 
			
		||||
			" record %lld\n",
 | 
			
		||||
			(long long)MREF(mref));
 | 
			
		||||
		goto put_err_out;
 | 
			
		||||
	}
 | 
			
		||||
	std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
 | 
			
		||||
			le16_to_cpu(ctx->attr->value_offset));
 | 
			
		||||
	ni->flags = std_info->file_attributes;
 | 
			
		||||
| 
						 | 
				
			
			@ -196,10 +203,9 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
 | 
			
		|||
	ni->last_data_change_time = std_info->last_data_change_time;
 | 
			
		||||
	ni->last_mft_change_time = std_info->last_mft_change_time;
 | 
			
		||||
	ni->last_access_time = std_info->last_access_time;
 | 
			
		||||
  		/* JPA insert v3 extensions if present */
 | 
			
		||||
                /* length may be seen as 72 (v1.x) or 96 (v3.x) */
 | 
			
		||||
	lthle = ctx->attr->length;
 | 
			
		||||
	if (le32_to_cpu(lthle) > sizeof(STANDARD_INFORMATION)) {
 | 
			
		||||
		/* Insert v3 extensions if present */
 | 
			
		||||
		/* length may be seen as 48 (v1.x) or 72 (v3.x) */
 | 
			
		||||
	if (le32_to_cpu(lthle) >= offsetof(STANDARD_INFORMATION, v3_end)) {
 | 
			
		||||
		set_nino_flag(ni, v3_Extensions);
 | 
			
		||||
		ni->owner_id = std_info->owner_id;
 | 
			
		||||
		ni->security_id = std_info->security_id;
 | 
			
		||||
| 
						 | 
				
			
			@ -225,9 +231,9 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
 | 
			
		|||
	l = ntfs_get_attribute_value_length(ctx->attr);
 | 
			
		||||
	if (!l)
 | 
			
		||||
		goto put_err_out;
 | 
			
		||||
	if (l > 0x40000) {
 | 
			
		||||
	if ((u64)l > 0x40000) {
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		ntfs_log_perror("Too large attrlist attribute (%lld), inode "
 | 
			
		||||
		ntfs_log_perror("Too large attrlist attribute (%llu), inode "
 | 
			
		||||
				"%lld", (long long)l, (long long)MREF(mref));
 | 
			
		||||
		goto put_err_out;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -760,13 +766,13 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
 | 
			
		|||
 | 
			
		||||
		/* JPA update v3.x extensions, ensuring consistency */
 | 
			
		||||
 | 
			
		||||
	lthle = ctx->attr->length;
 | 
			
		||||
	lthle = ctx->attr->value_length;
 | 
			
		||||
	lth = le32_to_cpu(lthle);
 | 
			
		||||
	if (test_nino_flag(ni, v3_Extensions)
 | 
			
		||||
	    && (lth <= sizeof(STANDARD_INFORMATION)))
 | 
			
		||||
	    && (lth < offsetof(STANDARD_INFORMATION, v3_end)))
 | 
			
		||||
		ntfs_log_error("bad sync of standard information\n");
 | 
			
		||||
 | 
			
		||||
	if (lth > sizeof(STANDARD_INFORMATION)) {
 | 
			
		||||
	if (lth >= offsetof(STANDARD_INFORMATION, v3_end)) {
 | 
			
		||||
		std_info->owner_id = ni->owner_id;
 | 
			
		||||
		std_info->security_id = ni->security_id;
 | 
			
		||||
		std_info->quota_charged = ni->quota_charged;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -368,12 +368,14 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
 | 
			
		|||
			/* Allocate the bitmap bit. */
 | 
			
		||||
			*byte |= bit;
 | 
			
		||||
			writeback = 1;
 | 
			
		||||
			if (vol->free_clusters <= 0) 
 | 
			
		||||
				ntfs_log_error("Non-positive free clusters "
 | 
			
		||||
					       "(%lld)!\n",
 | 
			
		||||
			if (NVolFreeSpaceKnown(vol)) {
 | 
			
		||||
				if (vol->free_clusters <= 0)
 | 
			
		||||
					ntfs_log_error("Non-positive free"
 | 
			
		||||
					       " clusters (%lld)!\n",
 | 
			
		||||
						(long long)vol->free_clusters);
 | 
			
		||||
			else	
 | 
			
		||||
				vol->free_clusters--; 
 | 
			
		||||
				else	
 | 
			
		||||
					vol->free_clusters--;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			/*
 | 
			
		||||
			 * Coalesce with previous run if adjacent LCNs.
 | 
			
		||||
| 
						 | 
				
			
			@ -602,7 +604,8 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
 | 
			
		|||
	ret = 0;
 | 
			
		||||
out:
 | 
			
		||||
	vol->free_clusters += nr_freed; 
 | 
			
		||||
	if (vol->free_clusters > vol->nr_clusters)
 | 
			
		||||
	if (NVolFreeSpaceKnown(vol)
 | 
			
		||||
	    && (vol->free_clusters > vol->nr_clusters))
 | 
			
		||||
		ntfs_log_error("Too many free clusters (%lld > %lld)!",
 | 
			
		||||
			       (long long)vol->free_clusters, 
 | 
			
		||||
			       (long long)vol->nr_clusters);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -172,6 +172,15 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
 | 
			
		|||
		cnt = vol->mftmirr_size - m;
 | 
			
		||||
		if (cnt > count)
 | 
			
		||||
			cnt = count;
 | 
			
		||||
		if ((m + cnt) > vol->mftmirr_na->initialized_size >>
 | 
			
		||||
				vol->mft_record_size_bits) {
 | 
			
		||||
			errno = ESPIPE;
 | 
			
		||||
			ntfs_log_perror("Trying to write non-allocated mftmirr"
 | 
			
		||||
				" records (%lld > %lld)", (long long)m + cnt,
 | 
			
		||||
				(long long)vol->mftmirr_na->initialized_size >>
 | 
			
		||||
				vol->mft_record_size_bits);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		bmirr = ntfs_malloc(cnt * vol->mft_record_size);
 | 
			
		||||
		if (!bmirr)
 | 
			
		||||
			return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -210,11 +219,26 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
 | 
			
		|||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *		Check the consistency of an MFT record
 | 
			
		||||
 *
 | 
			
		||||
 *	Make sure its general fields are safe, then examine all its
 | 
			
		||||
 *	attributes and apply generic checks to them.
 | 
			
		||||
 *	The attribute checks are skipped when a record is being read in
 | 
			
		||||
 *	order to collect its sequence number for creating a new record.
 | 
			
		||||
 *
 | 
			
		||||
 *	Returns 0 if the checks are successful
 | 
			
		||||
 *		-1 with errno = EIO otherwise
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref, 
 | 
			
		||||
			  MFT_RECORD *m)
 | 
			
		||||
{			  
 | 
			
		||||
	ATTR_RECORD *a;
 | 
			
		||||
	ATTR_TYPES previous_type;
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
	u32 offset;
 | 
			
		||||
	s32 space;
 | 
			
		||||
	
 | 
			
		||||
	if (!ntfs_is_file_record(m->magic)) {
 | 
			
		||||
		if (!NVolNoFixupWarn(vol))
 | 
			
		||||
| 
						 | 
				
			
			@ -231,13 +255,57 @@ int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
 | 
			
		|||
			       le32_to_cpu(m->bytes_allocated));
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (!NVolNoFixupWarn(vol)
 | 
			
		||||
	    && (le32_to_cpu(m->bytes_in_use) > vol->mft_record_size)) {
 | 
			
		||||
		ntfs_log_error("Record %llu has corrupt in-use size "
 | 
			
		||||
			       "(%u > %u)\n", (unsigned long long)MREF(mref),
 | 
			
		||||
			       (int)le32_to_cpu(m->bytes_in_use),
 | 
			
		||||
			       (int)vol->mft_record_size);
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
	if (le16_to_cpu(m->attrs_offset) & 7) {
 | 
			
		||||
		ntfs_log_error("Attributes badly aligned in record %llu\n",
 | 
			
		||||
			       (unsigned long long)MREF(mref));
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	a = (ATTR_RECORD *)((char *)m + le16_to_cpu(m->attrs_offset));
 | 
			
		||||
	if (p2n(a) < p2n(m) || (char *)a > (char *)m + vol->mft_record_size) {
 | 
			
		||||
		ntfs_log_error("Record %llu is corrupt\n",
 | 
			
		||||
			       (unsigned long long)MREF(mref));
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!NVolNoFixupWarn(vol)) {
 | 
			
		||||
		offset = le16_to_cpu(m->attrs_offset);
 | 
			
		||||
		space = le32_to_cpu(m->bytes_in_use) - offset;
 | 
			
		||||
		a = (ATTR_RECORD*)((char*)m + offset);
 | 
			
		||||
		previous_type = AT_STANDARD_INFORMATION;
 | 
			
		||||
		while ((space >= (s32)offsetof(ATTR_RECORD, resident_end))
 | 
			
		||||
		    && !le32_eq(a->type, AT_END)
 | 
			
		||||
		    && (le32_to_cpu(a->type) >= le32_to_cpu(previous_type))) {
 | 
			
		||||
			if ((le32_to_cpu(a->length) <= (u32)space)
 | 
			
		||||
			    && !(le32_to_cpu(a->length) & 7)) {
 | 
			
		||||
				if (!ntfs_attr_inconsistent(a, mref)) {
 | 
			
		||||
					previous_type = a->type;
 | 
			
		||||
					offset += le32_to_cpu(a->length);
 | 
			
		||||
					space -= le32_to_cpu(a->length);
 | 
			
		||||
					a = (ATTR_RECORD*)((char*)m + offset);
 | 
			
		||||
				} else
 | 
			
		||||
					goto err_out;
 | 
			
		||||
			} else {
 | 
			
		||||
				ntfs_log_error("Corrupted MFT record %llu\n",
 | 
			
		||||
				       (unsigned long long)MREF(mref));
 | 
			
		||||
				goto err_out;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
			/* We are supposed to reach an AT_END */
 | 
			
		||||
		if ((space < 4) || !le32_eq(a->type, AT_END)) {
 | 
			
		||||
			ntfs_log_error("Bad end of MFT record %llu\n",
 | 
			
		||||
				       (unsigned long long)MREF(mref));
 | 
			
		||||
			goto err_out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	ret = 0;
 | 
			
		||||
err_out:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -221,15 +221,24 @@ static int __ntfs_volume_release(ntfs_volume *v)
 | 
			
		|||
	return errno ? -1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ntfs_attr_setup_flag(ntfs_inode *ni)
 | 
			
		||||
static int ntfs_attr_setup_flag(ntfs_inode *ni)
 | 
			
		||||
{
 | 
			
		||||
	STANDARD_INFORMATION *si;
 | 
			
		||||
	s64 lth;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	si = ntfs_attr_readall(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, NULL);
 | 
			
		||||
	si = (STANDARD_INFORMATION*)ntfs_attr_readall(ni,
 | 
			
		||||
			AT_STANDARD_INFORMATION, AT_UNNAMED, 0, <h);
 | 
			
		||||
	if (si) {
 | 
			
		||||
		ni->flags = si->file_attributes;
 | 
			
		||||
		if ((u64)lth >= offsetof(STANDARD_INFORMATION, owner_id))
 | 
			
		||||
			ni->flags = si->file_attributes;
 | 
			
		||||
		free(si);
 | 
			
		||||
		r = 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		ntfs_log_error("Failed to get standard information of $MFT\n");
 | 
			
		||||
		r = -1;
 | 
			
		||||
	}
 | 
			
		||||
	return (r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -303,16 +312,19 @@ static int ntfs_mft_load(ntfs_volume *vol)
 | 
			
		|||
		ntfs_log_error("Failed to get value of $MFT/$ATTR_LIST.\n");
 | 
			
		||||
		goto io_error_exit;
 | 
			
		||||
	}
 | 
			
		||||
	if (l != vol->mft_ni->attr_list_size) {
 | 
			
		||||
	if ((l != vol->mft_ni->attr_list_size)
 | 
			
		||||
	    || (l < (s64)offsetof(ATTR_LIST_ENTRY, name))) {
 | 
			
		||||
		ntfs_log_error("Partial read of $MFT/$ATTR_LIST (%lld != "
 | 
			
		||||
			       "%u).\n", (long long)l,
 | 
			
		||||
			       vol->mft_ni->attr_list_size);
 | 
			
		||||
				"%u or < %d).\n", (long long)l,
 | 
			
		||||
				vol->mft_ni->attr_list_size,
 | 
			
		||||
				(int)offsetof(ATTR_LIST_ENTRY, name));
 | 
			
		||||
		goto io_error_exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
mft_has_no_attr_list:
 | 
			
		||||
 | 
			
		||||
	ntfs_attr_setup_flag(vol->mft_ni);
 | 
			
		||||
	if (ntfs_attr_setup_flag(vol->mft_ni))
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
	
 | 
			
		||||
	/* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -355,6 +367,11 @@ mft_has_no_attr_list:
 | 
			
		|||
			ntfs_log_perror("ntfs_mapping_pairs_decompress() failed");
 | 
			
		||||
			goto error_exit;
 | 
			
		||||
		}
 | 
			
		||||
		/* Make sure $DATA is the MFT itself */
 | 
			
		||||
		if (nrl->lcn != vol->mft_lcn) {
 | 
			
		||||
			ntfs_log_perror("The MFT is not self-contained");
 | 
			
		||||
			goto error_exit;
 | 
			
		||||
		}
 | 
			
		||||
		vol->mft_na->rl = nrl;
 | 
			
		||||
 | 
			
		||||
		/* Get the lowest vcn for the next extent. */
 | 
			
		||||
| 
						 | 
				
			
			@ -448,6 +465,12 @@ static int ntfs_mftmirr_load(ntfs_volume *vol)
 | 
			
		|||
		ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA");
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
	}
 | 
			
		||||
	if (vol->mftmirr_na->rl->lcn != vol->mftmirr_lcn) {
 | 
			
		||||
		ntfs_log_error("Bad $MFTMirr lcn 0x%llx, want 0x%llx\n",
 | 
			
		||||
				(long long)vol->mftmirr_na->rl->lcn,
 | 
			
		||||
				(long long)vol->mftmirr_lcn);
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -601,6 +624,10 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
 | 
			
		|||
	vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
 | 
			
		||||
	while (vol->mft_zone_end >= vol->nr_clusters) {
 | 
			
		||||
		mft_zone_size >>= 1;
 | 
			
		||||
		if (!mft_zone_size) {
 | 
			
		||||
			errno = EINVAL;
 | 
			
		||||
			goto error_exit;
 | 
			
		||||
		}
 | 
			
		||||
		vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
 | 
			
		||||
	}
 | 
			
		||||
	ntfs_log_debug("mft_zone_end = 0x%llx\n", (long long)vol->mft_zone_end);
 | 
			
		||||
| 
						 | 
				
			
			@ -949,6 +976,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
 | 
			
		|||
		}
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; (i < l) && (i < FILE_first_user); ++i)
 | 
			
		||||
		if (ntfs_mft_record_check(vol, FILE_MFT + i,
 | 
			
		||||
				(MFT_RECORD*)(m + i*vol->mft_record_size)))
 | 
			
		||||
			goto error_exit;
 | 
			
		||||
	l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
 | 
			
		||||
			vol->mft_record_size, m2);
 | 
			
		||||
	if (l != vol->mftmirr_size) {
 | 
			
		||||
| 
						 | 
				
			
			@ -958,6 +989,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
 | 
			
		|||
		}
 | 
			
		||||
		vol->mftmirr_size = l;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; (i < l) && (i < FILE_first_user); ++i)
 | 
			
		||||
		if (ntfs_mft_record_check(vol, FILE_MFT + i,
 | 
			
		||||
				(MFT_RECORD*)(m2 + i*vol->mft_record_size)))
 | 
			
		||||
			goto error_exit;
 | 
			
		||||
	ntfs_log_debug("Comparing $MFTMirr to $MFT...\n");
 | 
			
		||||
		/* Windows 10 does not update the full $MFTMirr any more */
 | 
			
		||||
	for (i = 0; (i < vol->mftmirr_size) && (i < FILE_first_user); ++i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,19 +1083,19 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
 | 
			
		|||
	na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
 | 
			
		||||
	if (!na) {
 | 
			
		||||
		ntfs_log_perror("Failed to open ntfs attribute");
 | 
			
		||||
		ntfs_inode_close(ni);
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
	 * Note: Normally, the upcase table has a length equal to 65536
 | 
			
		||||
	 * 2-byte Unicode characters but allow for different cases, so no
 | 
			
		||||
	 * checks done. Just check we don't overflow 32-bits worth of Unicode
 | 
			
		||||
	 * characters.
 | 
			
		||||
	 * 2-byte Unicode characters. Anyway we currently can only process
 | 
			
		||||
	 * such characters.
 | 
			
		||||
	 */
 | 
			
		||||
	if (na->data_size & ~0x1ffffffffULL) {
 | 
			
		||||
		ntfs_log_error("Error: Upcase table is too big (max 32-bit "
 | 
			
		||||
				"allowed).\n");
 | 
			
		||||
	if ((na->data_size - 2) & ~0x1fffeULL) {
 | 
			
		||||
		ntfs_log_error("Error: Upcase table is invalid (want size even "
 | 
			
		||||
				"<= 131072).\n");
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
		goto bad_upcase;
 | 
			
		||||
	}
 | 
			
		||||
	if (vol->upcase_len != na->data_size >> 1) {
 | 
			
		||||
		vol->upcase_len = na->data_size >> 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -1068,7 +1103,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
 | 
			
		|||
		free(vol->upcase);
 | 
			
		||||
		vol->upcase = ntfs_malloc(na->data_size);
 | 
			
		||||
		if (!vol->upcase)
 | 
			
		||||
			goto error_exit;
 | 
			
		||||
			goto bad_upcase;
 | 
			
		||||
	}
 | 
			
		||||
	/* Read in the $DATA attribute value into the buffer. */
 | 
			
		||||
	l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
 | 
			
		||||
| 
						 | 
				
			
			@ -1077,7 +1112,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
 | 
			
		|||
			       "(%lld != %lld).\n", (long long)l,
 | 
			
		||||
			       (long long)na->data_size);
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
		goto bad_upcase;
 | 
			
		||||
	}
 | 
			
		||||
	/* Done with the $UpCase mft record. */
 | 
			
		||||
	ntfs_attr_close(na);
 | 
			
		||||
| 
						 | 
				
			
			@ -1213,10 +1248,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
 | 
			
		|||
		ntfs_log_perror("Failed to open ntfs attribute");
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
	}
 | 
			
		||||
	/* Check we don't overflow 32-bits. */
 | 
			
		||||
	if (na->data_size > 0xffffffffLL) {
 | 
			
		||||
	/* Check we don't overflow 24-bits. */
 | 
			
		||||
	if ((u64)na->data_size > 0xffffffLL) {
 | 
			
		||||
		ntfs_log_error("Attribute definition table is too big (max "
 | 
			
		||||
			       "32-bit allowed).\n");
 | 
			
		||||
			       "24-bit allowed).\n");
 | 
			
		||||
		errno = EINVAL;
 | 
			
		||||
		goto error_exit;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1282,6 +1317,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	return vol;
 | 
			
		||||
bad_upcase :
 | 
			
		||||
	ntfs_attr_close(na);
 | 
			
		||||
	ntfs_inode_close(ni);
 | 
			
		||||
	goto error_exit;
 | 
			
		||||
io_error_exit:
 | 
			
		||||
	errno = EIO;
 | 
			
		||||
error_exit:
 | 
			
		||||
| 
						 | 
				
			
			@ -1855,8 +1894,10 @@ int ntfs_volume_get_free_space(ntfs_volume *vol)
 | 
			
		|||
 | 
			
		||||
		if (vol->free_mft_records < 0)
 | 
			
		||||
			ntfs_log_perror("Failed to calculate free MFT records");
 | 
			
		||||
		else
 | 
			
		||||
		else {
 | 
			
		||||
			NVolSetFreeSpaceKnown(vol);
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return (ret);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1155,7 +1155,7 @@ close_attr:
 | 
			
		|||
		if (!fstat(fileno(in),&st)) {
 | 
			
		||||
			s64 change_time = st.st_mtime*10000000LL
 | 
			
		||||
					+ NTFS_TIME_OFFSET;
 | 
			
		||||
			out->last_data_change_time = cpu_to_le64(change_time);
 | 
			
		||||
			out->last_data_change_time = cpu_to_sle64(change_time);
 | 
			
		||||
			ntfs_inode_update_times(out, 0);
 | 
			
		||||
		} else {
 | 
			
		||||
			ntfs_log_error("Failed to get the time stamp.\n");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -780,14 +780,19 @@ static ATTR_RECORD *find_unnamed_attr(MFT_RECORD *mrec, ATTR_TYPES type)
 | 
			
		|||
{
 | 
			
		||||
	ATTR_RECORD *a;
 | 
			
		||||
	u32 offset;
 | 
			
		||||
	s32 space;
 | 
			
		||||
 | 
			
		||||
			/* fetch the requested attribute */
 | 
			
		||||
	offset = le16_to_cpu(mrec->attrs_offset);
 | 
			
		||||
	space = le32_to_cpu(mrec->bytes_in_use) - offset;
 | 
			
		||||
	a = (ATTR_RECORD*)((char*)mrec + offset);
 | 
			
		||||
	while ((offset < le32_to_cpu(mrec->bytes_in_use))
 | 
			
		||||
	while ((space >= (s32)offsetof(ATTR_RECORD, resident_end))
 | 
			
		||||
	    && !le32_eq(a->type, AT_END)
 | 
			
		||||
	    && (le32_to_cpu(a->length) <= (u32)space)
 | 
			
		||||
	    && !(le32_to_cpu(a->length) & 7)
 | 
			
		||||
	    && (!le32_eq(a->type, type) || a->name_length)) {
 | 
			
		||||
		offset += le32_to_cpu(a->length);
 | 
			
		||||
		space -= le32_to_cpu(a->length);
 | 
			
		||||
		a = (ATTR_RECORD*)((char*)mrec + offset);
 | 
			
		||||
	}
 | 
			
		||||
	if ((offset >= le32_to_cpu(mrec->bytes_in_use))
 | 
			
		||||
| 
						 | 
				
			
			@ -823,7 +828,8 @@ static BOOL short_mft_selfloc_condition(struct MFT_SELF_LOCATED *selfloc)
 | 
			
		|||
			vol->mft_record_size, mft0)
 | 
			
		||||
				== vol->mft_record_size)
 | 
			
		||||
	    && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft0,
 | 
			
		||||
			vol->mft_record_size)) {
 | 
			
		||||
			vol->mft_record_size)
 | 
			
		||||
	    && !ntfs_mft_record_check(vol, 0, mft0)) {
 | 
			
		||||
		a = find_unnamed_attr(mft0,AT_DATA);
 | 
			
		||||
		if (a
 | 
			
		||||
		    && a->non_resident
 | 
			
		||||
| 
						 | 
				
			
			@ -961,7 +967,9 @@ static BOOL self_mapped_selfloc_condition(struct MFT_SELF_LOCATED *selfloc)
 | 
			
		|||
	if ((ntfs_pread(vol->dev, offs, vol->mft_record_size,
 | 
			
		||||
			mft1) == vol->mft_record_size)
 | 
			
		||||
	    && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft1,
 | 
			
		||||
			vol->mft_record_size)) {
 | 
			
		||||
			vol->mft_record_size)
 | 
			
		||||
	    && !ntfs_mft_record_check(vol, inum, mft1)) {
 | 
			
		||||
 | 
			
		||||
		lowest_vcn = (SELFLOC_LIMIT*vol->mft_record_size)
 | 
			
		||||
				>> vol->cluster_size_bits;
 | 
			
		||||
		a = find_unnamed_attr(mft1,AT_DATA);
 | 
			
		||||
| 
						 | 
				
			
			@ -1017,7 +1025,8 @@ static BOOL spare_record_selfloc_condition(struct MFT_SELF_LOCATED *selfloc)
 | 
			
		|||
	if ((ntfs_pread(vol->dev, offs, vol->mft_record_size,
 | 
			
		||||
			mft2) == vol->mft_record_size)
 | 
			
		||||
	    && !ntfs_mst_post_read_fixup((NTFS_RECORD*)mft2,
 | 
			
		||||
			vol->mft_record_size)) {
 | 
			
		||||
			vol->mft_record_size)
 | 
			
		||||
	    && !ntfs_mft_record_check(vol, inum, mft2)) {
 | 
			
		||||
		if (le64_cmpz(mft2->base_mft_record)
 | 
			
		||||
		    && !le16_andz(mft2->flags, MFT_RECORD_IN_USE)
 | 
			
		||||
		    && !find_unnamed_attr(mft2,AT_ATTRIBUTE_LIST)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -263,7 +263,7 @@ static const char *usage_msg =
 | 
			
		|||
"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
 | 
			
		||||
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
 | 
			
		||||
"Copyright (C) 2007-2021 Jean-Pierre Andre\n"
 | 
			
		||||
"Copyright (C) 2009 Erik Larsson\n"
 | 
			
		||||
"Copyright (C) 2009-2020 Erik Larsson\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"Usage:    %s [-o option[,...]] <device|image_file> <mount_point>\n"
 | 
			
		||||
"\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -4347,8 +4347,7 @@ static int ntfs_open(const char *device)
 | 
			
		|||
	if (ctx->ignore_case && ntfs_set_ignore_case(vol))
 | 
			
		||||
		goto err_out;
 | 
			
		||||
        
 | 
			
		||||
	vol->free_clusters = ntfs_attr_get_free_bits(vol->lcnbmp_na);
 | 
			
		||||
	if (vol->free_clusters < 0) {
 | 
			
		||||
	if (ntfs_volume_get_free_space(ctx->vol)) {
 | 
			
		||||
		ntfs_log_perror("Failed to read NTFS $Bitmap");
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -4368,9 +4367,12 @@ static int ntfs_open(const char *device)
 | 
			
		|||
	}
 | 
			
		||||
        
 | 
			
		||||
	errno = 0;
 | 
			
		||||
	goto out;
 | 
			
		||||
err_out:
 | 
			
		||||
	if (!errno)	/* Make sure to return an error */
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
out :
 | 
			
		||||
	return ntfs_volume_error(errno);
 | 
			
		||||
        
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void usage(void)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -198,7 +198,7 @@ static const char *usage_msg =
 | 
			
		|||
"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
 | 
			
		||||
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
 | 
			
		||||
"Copyright (C) 2007-2021 Jean-Pierre Andre\n"
 | 
			
		||||
"Copyright (C) 2009 Erik Larsson\n"
 | 
			
		||||
"Copyright (C) 2009-2020 Erik Larsson\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"Usage:    %s [-o option[,...]] <device|image_file> <mount_point>\n"
 | 
			
		||||
"\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -3965,6 +3965,9 @@ static struct fuse_operations ntfs_3g_ops = {
 | 
			
		|||
	.rmdir		= ntfs_fuse_rmdir,
 | 
			
		||||
#ifdef HAVE_UTIMENSAT
 | 
			
		||||
	.utimens	= ntfs_fuse_utimens,
 | 
			
		||||
#if defined(linux) & !defined(FUSE_INTERNAL) & (FUSE_VERSION < 30)
 | 
			
		||||
	.flag_utime_omit_ok = 1,
 | 
			
		||||
#endif /* defined(linux) & !defined(FUSE_INTERNAL) */
 | 
			
		||||
#else
 | 
			
		||||
	.utime		= ntfs_fuse_utime,
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -4053,8 +4056,7 @@ static int ntfs_open(const char *device)
 | 
			
		|||
				!ctx->hide_hid_files, ctx->hide_dot_files))
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	
 | 
			
		||||
	ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na);
 | 
			
		||||
	if (ctx->vol->free_clusters < 0) {
 | 
			
		||||
	if (ntfs_volume_get_free_space(ctx->vol)) {
 | 
			
		||||
		ntfs_log_perror("Failed to read NTFS $Bitmap");
 | 
			
		||||
		goto err_out;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -4073,9 +4075,12 @@ static int ntfs_open(const char *device)
 | 
			
		|||
	}
 | 
			
		||||
	
 | 
			
		||||
	errno = 0;
 | 
			
		||||
	goto out;
 | 
			
		||||
err_out:
 | 
			
		||||
	if (!errno)
 | 
			
		||||
		errno = EIO;
 | 
			
		||||
out :
 | 
			
		||||
	return ntfs_volume_error(errno);
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void usage(void)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue