Exemple #1
0
/**
 * ntfs_debug_runlist_dump - Dump a runlist.
 * @rl:
 *
 * Description...
 *
 * Returns:
 */
void ntfs_debug_runlist_dump(const runlist_element *rl)
{
	int i = 0;
	const char *lcn_str[5] = { "LCN_HOLE         ", "LCN_RL_NOT_MAPPED",
				   "LCN_ENOENT       ", "LCN_EINVAL       ",
				   "LCN_unknown      " };

	ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
	if (!rl) {
		ntfs_log_debug("Run list not present.\n");
		return;
	}
	ntfs_log_debug("VCN              LCN               Run length\n");
	do {
		LCN lcn = (rl + i)->lcn;

		if (lcn < (LCN)0) {
			int idx = -lcn - 1;

			if (idx > -LCN_EINVAL - 1)
				idx = 4;
			ntfs_log_debug("%-16llx %s %-16llx%s\n", rl[i].vcn, lcn_str[idx], rl[i].length, rl[i].length ? "" : " (runlist end)");
		} else
			ntfs_log_debug("%-16llx %-16llx  %-16llx%s\n", rl[i].vcn, rl[i].lcn, rl[i].length, rl[i].length ? "" : " (runlist end)");
	} while (rl[i++].length);
}
Exemple #2
0
/**
 * ntfs_device_size_get - return the size of a device in blocks
 * @dev:	open device
 * @block_size:	block size in bytes in which to return the result
 *
 * Return the number of @block_size sized blocks in the device described by the
 * open device @dev.
 *
 * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
 *
 * On error return -1 with errno set to the error code.
 */
s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
{
	s64 high, low;

	if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
		errno = EINVAL;
		return -1;
	}
#ifdef BLKGETSIZE64
	{	u64 size;

		if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
			ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
					(unsigned long long)size,
					(unsigned long long)size);
			return (s64)size / block_size;
		}
	}
#endif
#ifdef BLKGETSIZE
	{	unsigned long size;

		if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
			ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
					size, size);
			return (s64)size * 512 / block_size;
		}
	}
#endif
#ifdef FDGETPRM
	{       struct floppy_struct this_floppy;

		if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
			ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
					(unsigned long)this_floppy.size,
					(unsigned long)this_floppy.size);
			return (s64)this_floppy.size * 512 / block_size;
		}
	}
#endif
	/*
	 * We couldn't figure it out by using a specialized ioctl,
	 * so do binary search to find the size of the device.
	 */
	low = 0LL;
	for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
		low = high;
	while (low < high - 1LL) {
		const s64 mid = (low + high) / 2;

		if (!ntfs_device_offset_valid(dev, mid))
			low = mid;
		else
			high = mid;
	}
	dev->d_ops->seek(dev, 0LL, SEEK_SET);
	return (low + 1LL) / block_size;
}
Exemple #3
0
/**
 * ntfs_device_block_size_set - set block size of a device
 * @dev:	open device
 * @block_size: block size to set @dev to
 *
 * On success, return 0.
 * On error return -1 with errno set to the error code.
 *
 * The following error codes are defined:
 *	EINVAL		Input parameter error
 *	EOPNOTSUPP	System does not support BLKBSZSET ioctl
 *	ENOTTY		@dev is a file or a device not supporting BLKBSZSET
 */
int ntfs_device_block_size_set(struct ntfs_device *dev,
		int block_size __attribute__((unused)))
{
	if (!dev) {
		errno = EINVAL;
		return -1;
	}
#ifdef BLKBSZSET
	{
		size_t s_block_size = block_size;
		if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
			ntfs_log_debug("Used BLKBSZSET to set block size to "
					"%d bytes.\n", block_size);
			return 0;
		}
		/* If not a block device, pretend it was successful. */
		if (!NDevBlock(dev))
			return 0;
	}
#else
	/* If not a block device, pretend it was successful. */
	if (!NDevBlock(dev))
		return 0;
	errno = EOPNOTSUPP;
#endif
	return -1;
}
Exemple #4
0
/**
 * ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case
 * @s1:			first string
 * @s2:			second string
 * @n:			maximum unicode characters to compare
 * @upcase:		upcase table
 * @upcase_size:	upcase table size in Unicode characters
 *
 * Compare the first @n characters of the Unicode strings @s1 and @s2,
 * ignoring case. The strings in little endian format and appropriate
 * le16_to_cpu() conversion is performed on non-little endian machines.
 *
 * Each character is uppercased using the @upcase table before the comparison.
 *
 * The function returns an integer less than, equal to, or greater than zero
 * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
 * to be less than, to match, or be greater than @s2.
 */
int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
		const ntfschar *upcase, const u32 upcase_size)
{
	u16 c1, c2;
	size_t i;

#ifdef DEBUG
	if (!s1 || !s2 || !upcase) {
		ntfs_log_debug("ntfs_wcsncasecmp() received NULL pointer!\n");
		exit(1);
	}
#endif
	for (i = 0; i < n; ++i) {
		if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
			c1 = le16_to_cpu(upcase[c1]);
		if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
			c2 = le16_to_cpu(upcase[c2]);
		if (c1 < c2)
			return -1;
		if (c1 > c2)
			return 1;
		if (!c1)
			break;
	}
	return 0;
}
Exemple #5
0
void ntfs_ie_filename_dump(INDEX_ENTRY *ie)
{
	char *s;

	s = ntfs_ie_filename_get(ie);
	ntfs_log_debug("'%s' ", s);
	ntfs_attr_name_free(&s);
}
Exemple #6
0
/**
 * ntfs_device_sector_size_get - get sector size of a device
 * @dev:	open device
 *
 * On success, return the sector size in bytes of the device @dev.
 * On error return -1 with errno set to the error code.
 *
 * The following error codes are defined:
 *	EINVAL		Input parameter error
 *	EOPNOTSUPP	System does not support BLKSSZGET ioctl
 *	ENOTTY		@dev is a file or a device not supporting BLKSSZGET
 */
int ntfs_device_sector_size_get(struct ntfs_device *dev)
{
	if (!dev) {
		errno = EINVAL;
		return -1;
	}
#ifdef BLKSSZGET
	{
		int sect_size = 0;

		if (!dev->d_ops->ioctl(dev, BLKSSZGET, &sect_size)) {
			ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
					sect_size);
			return sect_size;
		}
	}
#elif defined(DIOCGSECTORSIZE)
	{
		/* FreeBSD */
		size_t sect_size = 0;

		if (!dev->d_ops->ioctl(dev, DIOCGSECTORSIZE, &sect_size)) {
			ntfs_log_debug("DIOCGSECTORSIZE sector size = %d bytes\n",
					(int) sect_size);
			return sect_size;
		}
	}
#elif defined(DKIOCGETBLOCKSIZE)
	{
		/* Mac OS X */
		uint32_t sect_size = 0;

		if (!dev->d_ops->ioctl(dev, DKIOCGETBLOCKSIZE, &sect_size)) {
			ntfs_log_debug("DKIOCGETBLOCKSIZE sector size = %d bytes\n",
					(int) sect_size);
			return sect_size;
		}
	}
#else
	errno = EOPNOTSUPP;
#endif
	return -1;
}
Exemple #7
0
static int ntfs_device_uefi_io_close(struct ntfs_device *dev)
{
	struct _uefi_fd *fd = DEV_FD(dev);
    ntfs_log_trace("dev %p\n", dev);

	//AsciiPrint("ntfs_device_uefi_io_close\n\r");
    // Get the device driver descriptor
    
    if (!fd) {
        errno = EBADF;
        return -1;
    }

    // Check that the device is actually open
    if (!NDevOpen(dev)) {
        ntfs_log_perror("device is not open\n");
        errno = EIO;
        return -1;
    }

    // Mark the device as closed
    NDevClearOpen(dev);
    NDevClearBlock(dev);

    // Flush the device (if dirty and not read-only)
    if (NDevDirty(dev) && !NDevReadOnly(dev)) {
        ntfs_log_debug("device is dirty, will now sync\n");

        // ...?

        // Mark the device as clean
        NDevClearDirty(dev);

    }

    // Flush and destroy the cache (if required)
    if (fd->cache) {
        //_NTFS_cache_flush(fd->cache);
        //_NTFS_cache_destructor(fd->cache);
    }

    // Shutdown the device interface
    /*const DISC_INTERFACE* interface = fd->interface;
    if (interface) {
        interface->shutdown();
    }*/

    // Free the device driver private data
    ntfs_free(dev->d_private);
    dev->d_private = NULL;

    return 0;
}
Exemple #8
0
/**
 * ntfs_device_unix_io_open - Open a device and lock it exclusively
 * @dev:
 * @flags:
 *
 * Description...
 *
 * Returns:
 */
static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
{
	struct flock flk;
	struct stat sbuf;
	int err;

	if (NDevOpen(dev)) {
		errno = EBUSY;
		return -1;
	}
	if (!(dev->d_private = ntfs_malloc(sizeof(int))))
		return -1;
	*(int*)dev->d_private = open(dev->d_name, flags);
	if (*(int*)dev->d_private == -1) {
		err = errno;
		goto err_out;
	}
	/* Setup our read-only flag. */
	if ((flags & O_RDWR) != O_RDWR)
		NDevSetReadOnly(dev);
	/* Acquire exclusive (mandatory) lock on the whole device. */
	memset(&flk, 0, sizeof(flk));
	if (NDevReadOnly(dev))
		flk.l_type = F_RDLCK;
	else
		flk.l_type = F_WRLCK;
	flk.l_whence = SEEK_SET;
	flk.l_start = flk.l_len = 0LL;
	if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
		err = errno;
		ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s "
				"for %s\n", dev->d_name, NDevReadOnly(dev) ?
				"reading" : "writing");
		if (close(DEV_FD(dev)))
			ntfs_log_perror("ntfs_device_unix_io_open: Warning: "
					"Could not close %s", dev->d_name);
		goto err_out;
	}
	/* Determine if device is a block device or not, ignoring errors. */
	if (!fstat(DEV_FD(dev), &sbuf) && S_ISBLK(sbuf.st_mode))
		NDevSetBlock(dev);
	/* Set our open flag. */
	NDevSetOpen(dev);
	return 0;
err_out:
	free(dev->d_private);
	dev->d_private = NULL;
	errno = err;
	return -1;
}
Exemple #9
0
/**
 * ntfs_names_collate - collate two Unicode names
 * @name1:	first Unicode name to compare
 * @name1_len:	length of first Unicode name to compare
 * @name2:	second Unicode name to compare
 * @name2_len:	length of second Unicode name to compare
 * @err_val:	if @name1 contains an invalid character return this value
 * @ic:		either CASE_SENSITIVE or IGNORE_CASE
 * @upcase:	upcase table (ignored if @ic is CASE_SENSITIVE)
 * @upcase_len:	upcase table size (ignored if @ic is CASE_SENSITIVE)
 *
 * ntfs_names_collate() collates two Unicode names and returns:
 *
 *  -1 if the first name collates before the second one,
 *   0 if the names match,
 *   1 if the second name collates before the first one, or
 * @err_val if an invalid character is found in @name1 during the comparison.
 *
 * The following characters are considered invalid: '"', '*', '<', '>' and '?'.
 */
int ntfs_names_collate(const ntfschar *name1, const u32 name1_len,
		const ntfschar *name2, const u32 name2_len,
		const int err_val __attribute__((unused)),
		const IGNORE_CASE_BOOL ic, const ntfschar *upcase,
		const u32 upcase_len)
{
	u32 cnt;
	ntfschar c1, c2;

#ifdef DEBUG
	if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) {
		ntfs_log_debug("ntfs_names_collate received NULL pointer!\n");
		exit(1);
	}
#endif
	for (cnt = 0; cnt < min(name1_len, name2_len); ++cnt) {
		c1 = le16_to_cpu(*name1);
		name1++;
		c2 = le16_to_cpu(*name2);
		name2++;
		if (ic) {
			if (c1 < upcase_len)
				c1 = le16_to_cpu(upcase[c1]);
			if (c2 < upcase_len)
				c2 = le16_to_cpu(upcase[c2]);
		}
#if 0
		if (c1 < 64 && legal_ansi_char_array[c1] & 8)
			return err_val;
#endif
		if (c1 < c2)
			return -1;
		if (c1 > c2)
			return 1;
	}
	if (name1_len < name2_len)
		return -1;
	if (name1_len == name2_len)
		return 0;
	/* name1_len > name2_len */
#if 0
	c1 = le16_to_cpu(*name1);
	if (c1 < 64 && legal_ansi_char_array[c1] & 8)
		return err_val;
#endif
	return 1;
}
/**
 * ntfs_log_parse_option - Act upon command line options
 * @option:	Option flag
 *
 * Delegate some of the work of parsing the command line.  All the options begin
 * with "--log-".  Options cause log levels to be enabled in @ntfs_log (the
 * global logging structure).
 *
 * Note: The "colour" option changes the logging handler.
 *
 * Returns:  TRUE  Option understood
 *          FALSE  Invalid log option
 */
BOOL1 ntfs_log_parse_option(const char *option)
{
	if (strcmp(option, "--log-debug") == 0) {
		ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
		return TRUE;
	} else if (strcmp(option, "--log-verbose") == 0) {
		ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
		return TRUE;
	} else if (strcmp(option, "--log-quiet") == 0) {
		ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
		return TRUE;
	} else if (strcmp(option, "--log-trace") == 0) {
		ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
		return TRUE;
	}

	ntfs_log_debug("Unknown logging option '%s'\n", option);
	return FALSE;
}
Exemple #11
0
/**
 * ntfs_device_partition_start_sector_get - get starting sector of a partition
 * @dev:	open device
 *
 * On success, return the starting sector of the partition @dev in the parent
 * block device of @dev.  On error return -1 with errno set to the error code.
 *
 * The following error codes are defined:
 *	EINVAL		Input parameter error
 *	EOPNOTSUPP	System does not support HDIO_GETGEO ioctl
 *	ENOTTY		@dev is a file or a device not supporting HDIO_GETGEO
 */
s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
{
	if (!dev) {
		errno = EINVAL;
		return -1;
	}
#ifdef HDIO_GETGEO
	{	struct hd_geometry geo;

		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
			ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
					geo.start, geo.start);
			return geo.start;
		}
	}
#else
	errno = EOPNOTSUPP;
#endif
	return -1;
}
Exemple #12
0
/**
 * ntfs_device_sector_size_get - get sector size of a device
 * @dev:	open device
 *
 * On success, return the sector size in bytes of the device @dev.
 * On error return -1 with errno set to the error code.
 *
 * The following error codes are defined:
 *	EINVAL		Input parameter error
 *	EOPNOTSUPP	System does not support BLKSSZGET ioctl
 *	ENOTTY		@dev is a file or a device not supporting BLKSSZGET
 */
int ntfs_device_sector_size_get(struct ntfs_device *dev)
{
	if (!dev) {
		errno = EINVAL;
		return -1;
	}
#ifdef BLKSSZGET
	{
		int sect_size = 0;

		if (!dev->d_ops->ioctl(dev, BLKSSZGET, &sect_size)) {
			ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
					sect_size);
			return sect_size;
		}
	}
#else
	errno = EOPNOTSUPP;
#endif
	return -1;
}
Exemple #13
0
/**
 * ntfs_device_sectors_per_track_get - get number of sectors per track of device
 * @dev:		open device
 *
 * On success, return the number of sectors per track on the device @dev.  On
 * error return -1 with errno set to the error code.
 *
 * The following error codes are defined:
 *	EINVAL		Input parameter error
 *	EOPNOTSUPP	System does not support HDIO_GETGEO ioctl
 *	ENOTTY		@dev is a file or a device not supporting HDIO_GETGEO
 */
int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
{
	if (!dev) {
		errno = EINVAL;
		return -1;
	}
#ifdef HDIO_GETGEO
	{	struct hd_geometry geo;

		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
			ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
					(unsigned)geo.sectors,
					(unsigned)geo.sectors);
			return geo.sectors;
		}
	}
#else
	errno = EOPNOTSUPP;
#endif
	return -1;
}
Exemple #14
0
/**
 * ntfs_ucsncmp - compare two little endian Unicode strings
 * @s1:		first string
 * @s2:		second string
 * @n:		maximum unicode characters to compare
 *
 * Compare the first @n characters of the Unicode strings @s1 and @s2,
 * The strings in little endian format and appropriate le16_to_cpu()
 * conversion is performed on non-little endian machines.
 *
 * The function returns an integer less than, equal to, or greater than zero
 * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
 * to be less than, to match, or be greater than @s2.
 */
int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
{
	ntfschar c1, c2;
	size_t i;

#ifdef DEBUG
	if (!s1 || !s2) {
		ntfs_log_debug("ntfs_wcsncmp() received NULL pointer!\n");
		exit(1);
	}
#endif
	for (i = 0; i < n; ++i) {
		c1 = le16_to_cpu(s1[i]);
		c2 = le16_to_cpu(s2[i]);
		if (c1 < c2)
			return -1;
		if (c1 > c2)
			return 1;
		if (!c1)
			break;
	}
	return 0;
}
Exemple #15
0
/**
 * ntfs_device_size_get - return the size of a device in blocks
 * @dev:	open device
 * @block_size:	block size in bytes in which to return the result
 *
 * Return the number of @block_size sized blocks in the device described by the
 * open device @dev.
 *
 * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
 *
 * On error return -1 with errno set to the error code.
 */
s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
{
	s64 high, low;

	if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
		errno = EINVAL;
		return -1;
	}
#ifdef BLKGETSIZE64
	{	u64 size;

		if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
			ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
					(unsigned long long)size,
					(unsigned long long)size);
			return (s64)size / block_size;
		}
	}
#endif
#ifdef BLKGETSIZE
	{	unsigned long size;

		if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
			ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
					size, size);
			return (s64)size * 512 / block_size;
		}
	}
#endif
#ifdef FDGETPRM
	{       struct floppy_struct this_floppy;

		if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
			ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
					(unsigned long)this_floppy.size,
					(unsigned long)this_floppy.size);
			return (s64)this_floppy.size * 512 / block_size;
		}
	}
#endif
#ifdef DIOCGMEDIASIZE
	{
		/* FreeBSD */
		off_t size;

		if (dev->d_ops->ioctl(dev, DIOCGMEDIASIZE, &size) >= 0) {
			ntfs_log_debug("DIOCGMEDIASIZE nr bytes = %llu (0x%llx)\n",
					(unsigned long long)size,
					(unsigned long long)size);
			return (s64)size / block_size;
		}
	}
#endif
#ifdef DKIOCGETBLOCKCOUNT
	{
		/* Mac OS X */
		uint64_t blocks;
		int sector_size;

		sector_size = ntfs_device_sector_size_get(dev);
		if (sector_size >= 0 && dev->d_ops->ioctl(dev,
			DKIOCGETBLOCKCOUNT, &blocks) >= 0)
		{
			ntfs_log_debug("DKIOCGETBLOCKCOUNT nr blocks = %llu (0x%llx)\n",
				(unsigned long long) blocks,
				(unsigned long long) blocks);
			return blocks * sector_size / block_size;
		}
	}
#endif
#ifdef __HAIKU__
	{
		off_t size = 0;

		partition_info partitionInfo;
		device_geometry geometry;
		
		if (dev->d_ops->ioctl(dev, B_GET_PARTITION_INFO, &partitionInfo) == 0)
			size = partitionInfo.size;
		else if (dev->d_ops->ioctl(dev, B_GET_GEOMETRY, &geometry) == 0) {
			size = (off_t)geometry.cylinder_count * geometry.sectors_per_track
				* geometry.head_count * geometry.bytes_per_sector;
		}
		
		if (size > 0)
			return (s64)size / block_size;
	}
#endif
	/*
	 * We couldn't figure it out by using a specialized ioctl,
	 * so do binary search to find the size of the device.
	 */
	low = 0LL;
	for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
		low = high;
	while (low < high - 1LL) {
		const s64 mid = (low + high) / 2;

		if (!ntfs_device_offset_valid(dev, mid))
			low = mid;
		else
			high = mid;
	}
	dev->d_ops->seek(dev, 0LL, SEEK_SET);
	return (low + 1LL) / block_size;
}
Exemple #16
0
/**
 * ntfs_index_lookup - find a key in an index and return its index entry
 * @key:	[IN] key for which to search in the index
 * @key_len:	[IN] length of @key in bytes
 * @icx:	[IN/OUT] context describing the index and the returned entry
 *
 * Before calling ntfs_index_lookup(), @icx must have been obtained from a
 * call to ntfs_index_ctx_get().
 *
 * Look for the @key in the index specified by the index lookup context @icx.
 * ntfs_index_lookup() walks the contents of the index looking for the @key.
 *
 * If the @key is found in the index, 0 is returned and @icx is setup to
 * describe the index entry containing the matching @key.  @icx->entry is the
 * index entry and @icx->data and @icx->data_len are the index entry data and
 * its length in bytes, respectively.
 *
 * If the @key is not found in the index, -1 is returned, errno = ENOENT and
 * @icx is setup to describe the index entry whose key collates immediately
 * after the search @key, i.e. this is the position in the index at which
 * an index entry with a key of @key would need to be inserted.
 *
 * If an error occurs return -1, set errno to error code and @icx is left
 * untouched.
 *
 * When finished with the entry and its data, call ntfs_index_ctx_put() to free
 * the context and other associated resources.
 *
 * If the index entry was modified, call ntfs_index_entry_mark_dirty() before
 * the call to ntfs_index_ctx_put() to ensure that the changes are written
 * to disk.
 */
int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *icx)
{
	VCN old_vcn, vcn;
	ntfs_inode *ni = icx->ni;
	INDEX_ROOT *ir;
	INDEX_ENTRY *ie;
	INDEX_BLOCK *ib = NULL;
	int ret, err = 0;

	ntfs_log_trace("Entering\n");
	
	if (!key || key_len <= 0) {
		errno = EINVAL;
		ntfs_log_perror("key: %p  key_len: %d", key, key_len);
		return -1;
	}

	ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &icx->actx);
	if (!ir) {
		if (errno == ENOENT)
			errno = EIO;
		return -1;
	}
	
	icx->block_size = le32_to_cpu(ir->index_block_size);
	if (icx->block_size < NTFS_BLOCK_SIZE) {
		errno = EINVAL;
		ntfs_log_perror("Index block size (%d) is smaller than the "
				"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE);
		goto err_out;
	}

	if (ni->vol->cluster_size <= icx->block_size)
		icx->vcn_size_bits = ni->vol->cluster_size_bits;
	else
		icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
			/* get the appropriate collation function */
	icx->collate = ntfs_get_collate_function(ir->collation_rule);
	if (!icx->collate) {
		err = errno = EOPNOTSUPP;
		ntfs_log_perror("Unknown collation rule 0x%x", 
				(unsigned)le32_to_cpu(ir->collation_rule));
		goto err_out;
	}
	
	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;
		goto err_out;
	}
	
	icx->ir = ir;
	
	if (ret != STATUS_KEEP_SEARCHING) {
		/* STATUS_OK or STATUS_NOT_FOUND */
		err = errno;
		icx->is_in_root = TRUE;
		icx->parent_vcn[icx->pindex] = old_vcn;
		goto done;
	}
	
	/* Child node present, descend into it. */
	
	icx->ia_na = ntfs_ia_open(icx, ni);
	if (!icx->ia_na)
		goto err_out;
	
	ib = ntfs_malloc(icx->block_size);
	if (!ib) {
		err = errno;
		goto err_out;
	}
	
descend_into_child_node:

	icx->parent_vcn[icx->pindex] = old_vcn;
	if (ntfs_icx_parent_inc(icx)) {
		err = errno;
		goto err_out;
	}
	old_vcn = vcn;

	ntfs_log_debug("Descend into node with VCN %lld\n", (long long)vcn);
	
	if (ntfs_ib_read(icx, vcn, ib))
		goto err_out;
	
	ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie);
	if (ret != STATUS_KEEP_SEARCHING) {
		err = errno;
		if (ret == STATUS_ERROR)
			goto err_out;
		
		/* STATUS_OK or STATUS_NOT_FOUND */
		icx->is_in_root = FALSE;
		icx->ib = ib;
		icx->parent_vcn[icx->pindex] = vcn;
		goto done;
	}

	if ((ib->index.ih_flags & NODE_MASK) == LEAF_NODE) {
		ntfs_log_error("Index entry with child node found in a leaf "
			       "node in inode 0x%llx.\n",
			       (unsigned long long)ni->mft_no);
		goto err_out;
	}
	
	goto descend_into_child_node;
err_out:
	free(ib);
	if (!err)
		err = EIO;
	errno = err;
	return -1;
done:
	icx->entry = ie;
	icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key);
	icx->data_len = le16_to_cpu(ie->key_length);
	ntfs_log_trace("Done.\n");
	if (err) {
		errno = err;
		return -1;
	}
	return 0;

}
Exemple #17
0
/** 
 * Find a key in the index block.
 * 
 * Return values:
 *   STATUS_OK with errno set to ESUCCESS if we know for sure that the 
 *             entry exists and @ie_out points to this entry.
 *   STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the
 *                    entry doesn't exist and @ie_out is the insertion point.
 *   STATUS_KEEP_SEARCHING if we can't answer the above question and
 *                         @vcn will contain the node index block.
 *   STATUS_ERROR with errno set if on unexpected error during lookup.
 */
static int ntfs_ie_lookup(const void *key, const int key_len,
			  ntfs_index_context *icx, INDEX_HEADER *ih,
			  VCN *vcn, INDEX_ENTRY **ie_out)
{
	INDEX_ENTRY *ie;
	u8 *index_end;
	int rc, item = 0;
	 
	ntfs_log_trace("Entering\n");
	
	index_end = ntfs_ie_get_end(ih);
	
	/*
	 * Loop until we exceed valid memory (corruption case) or until we
	 * reach the last entry.
	 */
	for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) {
		/* Bounds checks. */
		if ((u8 *)ie + sizeof(INDEX_ENTRY_HEADER) > index_end ||
		    (u8 *)ie + le16_to_cpu(ie->length) > index_end) {
			errno = ERANGE;
			ntfs_log_error("Index entry out of bounds in inode "
				       "%llu.\n",
				       (unsigned long long)icx->ni->mft_no);
			return STATUS_ERROR;
		}
		/*
		 * The last entry cannot contain a key.  It can however contain
		 * a pointer to a child node in the B+tree so we just break out.
		 */
		if (ntfs_ie_end(ie))
			break;
		/*
		 * Not a perfect match, need to do full blown collation so we
		 * know which way in the B+tree we have to go.
		 */
		if (!icx->collate) {
			ntfs_log_error("Collation function not defined\n");
			errno = EOPNOTSUPP;
			return STATUS_ERROR;
		}
		rc = icx->collate(icx->ni->vol, key, key_len,
					&ie->key, le16_to_cpu(ie->key_length));
		if (rc == NTFS_COLLATION_ERROR) {
			ntfs_log_error("Collation error. Perhaps a filename "
				       "contains invalid characters?\n");
			errno = ERANGE;
			return STATUS_ERROR;
		}
		/*
		 * If @key collates before the key of the current entry, there
		 * is definitely no such key in this index but we might need to
		 * descend into the B+tree so we just break out of the loop.
		 */
		if (rc == -1)
			break;
		
		if (!rc) {
			*ie_out = ie;
			errno = 0;
			icx->parent_pos[icx->pindex] = item;
			return STATUS_OK;
		}
		
		item++;
	}
	/*
	 * We have finished with this index block without success. Check for the
	 * presence of a child node and if not present return with errno ENOENT,
	 * otherwise we will keep searching in another index block.
	 */
	if (!(ie->ie_flags & INDEX_ENTRY_NODE)) {
		ntfs_log_debug("Index entry wasn't found.\n");
		*ie_out = ie;
		errno = ENOENT;
		return STATUS_NOT_FOUND;
	}
	
	/* Get the starting vcn of the index_block holding the child node. */
	*vcn = ntfs_ie_get_vcn(ie);
	if (*vcn < 0) {
		errno = EINVAL;
		ntfs_log_perror("Negative vcn in inode %llu",
			       	(unsigned long long)icx->ni->mft_no);
		return STATUS_ERROR;
	}

	ntfs_log_trace("Parent entry number %d\n", item);
	icx->parent_pos[icx->pindex] = item;
	
	return STATUS_KEEP_SEARCHING;
}
Exemple #18
0
/**
 * ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
 * @vol:	ntfs_volume to setup
 * @bs:		buffer containing ntfs boot sector to parse
 *
 * Parse the ntfs bootsector @bs and setup the ntfs volume @vol with the
 * obtained values.
 *
 * Return 0 on success or -1 on error with errno set to the error code EINVAL.
 */
int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
{
	s64 sectors;
	u8  sectors_per_cluster;
	s8  c;

	/* We return -1 with errno = EINVAL on error. */
	errno = EINVAL;

	vol->sector_size = le16_to_cpu(bs->bpb.bytes_per_sector);
	vol->sector_size_bits = ffs(vol->sector_size) - 1;
	ntfs_log_debug("SectorSize = 0x%x\n", vol->sector_size);
	ntfs_log_debug("SectorSizeBits = %u\n", vol->sector_size_bits);
	/*
	 * The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
	 * below or equal the number_of_clusters) really belong in the
	 * ntfs_boot_sector_is_ntfs but in this way we can just do this once.
	 */
	sectors_per_cluster = bs->bpb.sectors_per_cluster;
	ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
	if (sectors_per_cluster & (sectors_per_cluster - 1)) {
		ntfs_log_error("sectors_per_cluster (%d) is not a power of 2."
			       "\n", sectors_per_cluster);
		return -1;
	}
	
	sectors = sle64_to_cpu(bs->number_of_sectors);
	ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
	if (!sectors) {
		ntfs_log_error("Volume size is set to zero.\n");
		return -1;
	}
	if (vol->dev->d_ops->seek(vol->dev, 
				  (sectors - 1) << vol->sector_size_bits,
				  SEEK_SET) == -1) {
		ntfs_log_perror("Failed to read last sector (%lld)",
			       	(long long)sectors);
		ntfs_log_error("%s", last_sector_error);
		return -1;
	}
	
	vol->nr_clusters =  sectors >> (ffs(sectors_per_cluster) - 1);

	vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
	vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
	ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
	ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
	if (vol->mft_lcn     > vol->nr_clusters ||
	    vol->mftmirr_lcn > vol->nr_clusters) {
		ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
			      "greater than the number of clusters (%lld).\n",
			      (long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
			      (long long)vol->nr_clusters);
		return -1;
	}
	
	vol->cluster_size = sectors_per_cluster * vol->sector_size;
	if (vol->cluster_size & (vol->cluster_size - 1)) {
		ntfs_log_error("cluster_size (%d) is not a power of 2.\n",
			       vol->cluster_size);
		return -1;
	}
	vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
	/*
	 * Need to get the clusters per mft record and handle it if it is
	 * negative. Then calculate the mft_record_size. A value of 0x80 is
	 * illegal, thus signed char is actually ok!
	 */
	c = bs->clusters_per_mft_record;
	ntfs_log_debug("ClusterSize = 0x%x\n", (unsigned)vol->cluster_size);
	ntfs_log_debug("ClusterSizeBits = %u\n", vol->cluster_size_bits);
	ntfs_log_debug("ClustersPerMftRecord = 0x%x\n", c);
	/*
	 * When clusters_per_mft_record is negative, it means that it is to
	 * be taken to be the negative base 2 logarithm of the mft_record_size
	 * min bytes. Then:
	 *	 mft_record_size = 2^(-clusters_per_mft_record) bytes.
	 */
	if (c < 0)
		vol->mft_record_size = 1 << -c;
	else
		vol->mft_record_size = c << vol->cluster_size_bits;
	if (vol->mft_record_size & (vol->mft_record_size - 1)) {
		ntfs_log_error("mft_record_size (%d) is not a power of 2.\n",
			       vol->mft_record_size);
		return -1;
	}
	vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
	ntfs_log_debug("MftRecordSize = 0x%x\n", (unsigned)vol->mft_record_size);
	ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
	/* Same as above for INDX record. */
	c = bs->clusters_per_index_record;
	ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
	if (c < 0)
		vol->indx_record_size = 1 << -c;
	else
		vol->indx_record_size = c << vol->cluster_size_bits;
	vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
	ntfs_log_debug("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size);
	ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
	/*
	 * Work out the size of the MFT mirror in number of mft records. If the
	 * cluster size is less than or equal to the size taken by four mft
	 * records, the mft mirror stores the first four mft records. If the
	 * cluster size is bigger than the size taken by four mft records, the
	 * mft mirror contains as many mft records as will fit into one
	 * cluster.
	 */
	if (vol->cluster_size <= 4 * vol->mft_record_size)
		vol->mftmirr_size = 4;
	else
		vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
	return 0;
}
Exemple #19
0
ntfs_vd *ntfsMount (const char *name, struct _NTFS_VOLUME *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags)
{
    ntfs_vd *vd = NULL;
    struct _uefi_fd *fd = NULL;
	const devoptab_t *mnt;

	//Print(L"ntfsMount %a\n", name);

	//CpuBreakpoint();

	// Sanity check
    if (!name || !interface) {
		//Print(L"ntfsMount EINVAL\n");
        errno = EINVAL;
        return false;
    }

    // Initialise ntfs-3g
	ntfsInit();

	mnt = ntfsGetDevice(name, false);

    // Check that the requested mount name is free
    if (mnt) {
		//Print(L"ntfsMount EADDRINUSE\n");
        errno = 99; //EADDRINUSE;
	
		return (ntfs_vd*) mnt->deviceData;	// previous mnt data!
    }


    // Allocate the volume descriptor
    vd = (ntfs_vd*)ntfs_alloc(sizeof(ntfs_vd));
    if (!vd) {
		//Print(L"ntfsMount ENOMEM\n");
        errno = ENOMEM;
        return false;
    }
	else {
		//Print(L"ntfsMount ntfs_vd!\n");
	}

    // Setup the volume descriptor
	//Print(L"vd.id! [%x]\n", vd);
    vd->id = 0;//interface->ioType;
    //Print(L"vd.flags!\n");
	vd->flags = 0;
    vd->uid = 0;
    vd->gid = 0;
    vd->fmask = 0;
    vd->dmask = 0;
    vd->atime = ((flags & NTFS_UPDATE_ACCESS_TIMES) ? ATIME_ENABLED : ATIME_DISABLED);
    vd->showHiddenFiles = (flags & NTFS_SHOW_HIDDEN_FILES);
    vd->showSystemFiles = (flags & NTFS_SHOW_SYSTEM_FILES);

	//Print(L"invoking ntfs_alloc!\n");
    // Allocate the device driver descriptor
    fd = (struct _uefi_fd *)ntfs_alloc(sizeof(struct _uefi_fd));
    if (!fd) {
		//Print(L"ntfsMount ENOMEM(2)\n");
		ntfs_free(vd);
        errno = ENOMEM;
        return false;
    }
	else
	{
		//Print(L"ntfs_alloc uefi_fd\n");
	}

    // Setup the device driver descriptor
    fd->interface = interface;
    fd->startSector = startSector;
    fd->sectorSize = 0x200;
	fd->sectorCount = 0x200;
    fd->cachePageCount = cachePageCount;
    fd->cachePageSize = cachePageSize;

    // Allocate the device driver
    vd->dev = ntfs_device_alloc(name, 0, &ntfs_device_uefi_io_ops, fd);
    if (!vd->dev) {
		//Print(L"ntfsMount ntfs_device_alloc failed\n");
        ntfs_free(fd);
        ntfs_free(vd);
        return false;
    }
	//Print(L"ntfs_device_alloc success\n");

    // Build the mount flags
    if (flags & NTFS_READ_ONLY)
    	vd->flags |= NTFS_MNT_RDONLY;
    
    if (flags & NTFS_RECOVER)
        vd->flags |= NTFS_MNT_RECOVER;
    if (flags & NTFS_IGNORE_HIBERFILE)
        vd->flags |= NTFS_MNT_IGNORE_HIBERFILE;

    if (vd->flags & NTFS_MNT_RDONLY)
        ntfs_log_debug("Mounting \"%s\" as read-only\n", name);

    // Mount the device
	//Print(L"Invoking ntfs_device_mount\n");
    vd->vol = ntfs_device_mount(vd->dev, vd->flags);
    if (!vd->vol) {
        switch(ntfs_volume_error(errno)) {
            case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
            case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
            case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
            case NTFS_VOLUME_UNCLEAN_UNMOUNT: errno = EDIRTY; break;
            default: errno = EINVAL; break;
        }
        ntfs_device_free(vd->dev);
        ntfs_free(vd);
		//Print(L"ntfsMount ntfs_device_mount FAILED (%x)\n", errno);
        return NULL;
    }

	if (flags & NTFS_IGNORE_CASE)
		ntfs_set_ignore_case(vd->vol);

    // Initialise the volume descriptor
    if (ntfsInitVolume(vd)) {
        ntfs_umount(vd->vol, true);
        ntfs_free(vd);
		//Print(L"ntfsMount ntfsInitVolume failed\n");
        return NULL;
    }

    // Add the device to the devoptab table
    if (ntfsAddDevice(name, vd)) {
		//Print(L"ntfsMount ntfsAddDevice failed\n");
        ntfsDeinitVolume(vd);
        ntfs_umount(vd->vol, true);
        ntfs_free(vd);
        return NULL;
    }

	//Print(L"ntfsMount done.\n");
    return vd;
}
Exemple #20
0
static int ntfs_device_get_geo(struct ntfs_device *dev)
{
	int err;

	if (!dev) {
		errno = EINVAL;
		return -1;
	}
	err = EOPNOTSUPP;
#ifdef ENABLE_HD
	{
		hd_data_t *hddata;
		hd_t *hd, *devlist, *partlist = NULL;
		str_list_t *names;
		hd_res_t *res;
		const int d_name_len = strlen(dev->d_name) + 1;
		int done = 0;

		hddata = calloc(1, sizeof(*hddata));
		if (!hddata) {
			err = ENOMEM;
			goto skip_hd;
		}
		/* List all "disk" class devices on the system. */
		devlist = hd_list(hddata, hw_disk, 1, NULL);
		if (!devlist) {
			free(hddata);
			err = ENOMEM;
			goto skip_hd;
		}
		/*
		 * Loop over each disk device looking for the device with the
		 * same unix name as @dev.
		 */
		for (hd = devlist; hd; hd = hd->next) {
			if (hd->unix_dev_name && !strncmp(dev->d_name,
					hd->unix_dev_name, d_name_len))
				goto got_hd;
			if (hd->unix_dev_name2 && !strncmp(dev->d_name,
					hd->unix_dev_name2, d_name_len))
				goto got_hd;
			for (names = hd->unix_dev_names; names;
					names = names->next) {
				if (names->str && !strncmp(dev->d_name,
						names->str, d_name_len))
					goto got_hd;
			}
		}
		/*
		 * Device was not a whole disk device.  Unless it is a file it
		 * is likely to be a partition device.  List all "partition"
		 * class devices on the system.
		 */
		partlist = hd_list(hddata, hw_partition, 1, NULL);
		for (hd = partlist; hd; hd = hd->next) {
			if (hd->unix_dev_name && !strncmp(dev->d_name,
					hd->unix_dev_name, d_name_len))
				goto got_part_hd;
			if (hd->unix_dev_name2 && !strncmp(dev->d_name,
					hd->unix_dev_name2, d_name_len))
				goto got_part_hd;
			for (names = hd->unix_dev_names; names;
					names = names->next) {
				if (names->str && !strncmp(dev->d_name,
						names->str, d_name_len))
					goto got_part_hd;
			}
		}
		/* Failed to find the device.  Stop trying and clean up. */
		goto end_hd;
got_part_hd:
		/* Get the whole block device the partition device is on. */
		hd = hd_get_device_by_idx(hddata, hd->attached_to);
		if (!hd)
			goto end_hd;
got_hd:
		/*
		 * @hd is now the whole block device either being formatted or
		 * that the partition being formatted is on.
		 *
		 * Loop over each resource of the disk device looking for the
		 * BIOS legacy geometry obtained from EDD which is what Windows
		 * needs to boot.
		 */
		for (res = hd->res; res; res = res->next) {
			/* geotype 3 is BIOS legacy. */
			if (res->any.type != res_disk_geo ||
					res->disk_geo.geotype != 3)
				continue;
			dev->d_heads = res->disk_geo.heads;
			dev->d_sectors_per_track = res->disk_geo.sectors;
			done = 1;
		}
end_hd:
		if (partlist)
			hd_free_hd_list(partlist);
		hd_free_hd_list(devlist);
		hd_free_hd_data(hddata);
		free(hddata);
		if (done) {
			ntfs_log_debug("EDD/BIOD legacy heads = %u, sectors "
					"per track = %u\n", dev->d_heads,
					dev->d_sectors_per_track);
			return 0;
		}
	}
skip_hd:
#endif
#ifdef HDIO_GETGEO
	{	struct hd_geometry geo;

		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
			dev->d_heads = geo.heads;
			dev->d_sectors_per_track = geo.sectors;
			ntfs_log_debug("HDIO_GETGEO heads = %u, sectors per "
					"track = %u\n", dev->d_heads,
					dev->d_sectors_per_track);
			return 0;
		}
		err = errno;
	}
#endif
	errno = err;
	return -1;
}
Exemple #21
0
/**
 * ntfs_fek_import_from_raw
 */
static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, unsigned fek_size)
{
    ntfs_fek *fek;
    u32 key_size, wanted_key_size, gcry_algo;
    int gcry_mode;
    gcry_error_t err;
    ntfs_desx_ctx *ctx;

    key_size = le32_to_cpup(fek_buf);
    ntfs_log_debug("key_size 0x%x\n", key_size);
    if (key_size + 16 > fek_size) {
        ntfs_log_debug("Invalid FEK.  It was probably decrypted with "
                       "the incorrect RSA key.");
        errno = EINVAL;
        return NULL;
    }
    fek = malloc(((((sizeof(*fek) + 7) & ~7) + key_size + 7) & ~7) +
                 sizeof(gcry_cipher_hd_t));
    if (!fek) {
        errno = ENOMEM;
        return NULL;
    }
    ctx = &fek->desx_ctx;
    fek->alg_id = *(le32*)(fek_buf + 8);
    //ntfs_log_debug("alg_id 0x%x\n", le32_to_cpu(fek->alg_id));
    fek->key_data = (u8*)fek + ((sizeof(*fek) + 7) & ~7);
    memcpy(fek->key_data, fek_buf + 16, key_size);
    fek->des_gcry_cipher_hd_ptr = NULL;
    *(gcry_cipher_hd_t***)(fek->key_data + ((key_size + 7) & ~7)) =
        &fek->des_gcry_cipher_hd_ptr;
    switch (fek->alg_id) {
    case CALG_DESX:
        wanted_key_size = 16;
        gcry_algo = GCRY_CIPHER_DES;
        gcry_mode = GCRY_CIPHER_MODE_ECB;
        break;
    case CALG_3DES:
        wanted_key_size = 24;
        gcry_algo = GCRY_CIPHER_3DES;
        gcry_mode = GCRY_CIPHER_MODE_CBC;
        break;
    case CALG_AES_256:
        wanted_key_size = 32;
        gcry_algo = GCRY_CIPHER_AES256;
        gcry_mode = GCRY_CIPHER_MODE_CBC;
        break;
    default:
        wanted_key_size = 8;
        gcry_algo = GCRY_CIPHER_DES;
        gcry_mode = GCRY_CIPHER_MODE_CBC;
        if (fek->alg_id == CALG_DES)
            ntfs_log_error("DES is not supported at present\n");
        else
            ntfs_log_error("Unknown crypto algorithm 0x%x\n",
                           le32_to_cpu(fek->alg_id));
        ntfs_log_error(".  Please email %s and say that you saw this "
                       "message.  We will then try to implement "
                       "support for this algorithm.\n", NTFS_DEV_LIST);
        err = EOPNOTSUPP;
        goto out;
    }
    if (key_size != wanted_key_size) {
        ntfs_log_error("%s key of %u bytes but needed size is %u "
                       "bytes, assuming corrupt or incorrect key.  "
                       "Aborting.\n",
                       gcry_cipher_algo_name(gcry_algo),
                       (unsigned)key_size, (unsigned)wanted_key_size);
        err = EIO;
        goto out;
    }
    err = gcry_cipher_open(&fek->gcry_cipher_hd, gcry_algo,
                           gcry_mode, 0);

    if (err != GPG_ERR_NO_ERROR) {
        ntfs_log_error("gcry_cipher_open() failed: %s\n",
                       gcry_strerror(err));
        err = EINVAL;
        goto out;
    }
    if (fek->alg_id == CALG_DESX) {
        err = ntfs_desx_key_expand(fek->key_data, (u32*)ctx->des_key,
                                   &ctx->out_whitening, &ctx->in_whitening);
        if (err == GPG_ERR_NO_ERROR)
            err = gcry_cipher_setkey(fek->gcry_cipher_hd,
                                     ctx->des_key, 8);
    } else {
        err = gcry_cipher_setkey(fek->gcry_cipher_hd, fek->key_data,
                                 key_size);
    }
    if (err != GPG_ERR_NO_ERROR) {
        ntfs_log_error("gcry_cipher_setkey() failed: %s\n",
                       gcry_strerror(err));
        gcry_cipher_close(fek->gcry_cipher_hd);
        err = EINVAL;
        goto out;
    }
    return fek;
out:
    free(fek);
    errno = err;
    return NULL;
}
Exemple #22
0
/**
 * ntfs_boot_sector_is_ntfs - check if buffer contains a valid ntfs boot sector
 * @b:		buffer containing putative boot sector to analyze
 * @silent:	if zero, output progress messages to stderr
 *
 * Check if the buffer @b contains a valid ntfs boot sector. The buffer @b
 * must be at least 512 bytes in size.
 *
 * If @silent is zero, output progress messages to stderr. Otherwise, do not
 * output any messages (except when configured with --enable-debug in which
 * case warning/debug messages may be displayed).
 *
 * Return TRUE if @b contains a valid ntfs boot sector and FALSE if not.
 */
BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
{
	u32 i;
	BOOL ret = FALSE;

	ntfs_log_debug("Beginning bootsector check.\n");

	ntfs_log_debug("Checking OEMid, NTFS signature.\n");
	if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS    " */
		ntfs_log_error("NTFS signature is missing.\n");
		goto not_ntfs;
	}

	ntfs_log_debug("Checking bytes per sector.\n");
	if (le16_to_cpu(b->bpb.bytes_per_sector) <  256 ||
	    le16_to_cpu(b->bpb.bytes_per_sector) > 4096) {
		ntfs_log_error("Unexpected bytes per sector value (%d).\n", 
			       le16_to_cpu(b->bpb.bytes_per_sector));
		goto not_ntfs;
	}

	ntfs_log_debug("Checking sectors per cluster.\n");
	switch (b->bpb.sectors_per_cluster) {
	case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
		break;
	default:
		ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
			       b->bpb.sectors_per_cluster);
		goto not_ntfs;
	}

	ntfs_log_debug("Checking cluster size.\n");
	i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) * 
		b->bpb.sectors_per_cluster;
	if (i > 65536) {
		ntfs_log_error("Unexpected cluster size (%d).\n", i);
		goto not_ntfs;
	}

	ntfs_log_debug("Checking reserved fields are zero.\n");
	if (le16_to_cpu(b->bpb.reserved_sectors) ||
	    le16_to_cpu(b->bpb.root_entries) ||
	    le16_to_cpu(b->bpb.sectors) ||
	    le16_to_cpu(b->bpb.sectors_per_fat) ||
	    le32_to_cpu(b->bpb.large_sectors) ||
	    b->bpb.fats) {
		ntfs_log_error("Reserved fields aren't zero "
			       "(%d, %d, %d, %d, %d, %d).\n",
			       le16_to_cpu(b->bpb.reserved_sectors),
			       le16_to_cpu(b->bpb.root_entries),
			       le16_to_cpu(b->bpb.sectors),
			       le16_to_cpu(b->bpb.sectors_per_fat),
			       le32_to_cpu(b->bpb.large_sectors),
			       b->bpb.fats);
		goto not_ntfs;
	}

	ntfs_log_debug("Checking clusters per mft record.\n");
	if ((u8)b->clusters_per_mft_record < 0xe1 ||
	    (u8)b->clusters_per_mft_record > 0xf7) {
		switch (b->clusters_per_mft_record) {
		case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
			break;
		default:
			ntfs_log_error("Unexpected clusters per mft record "
				       "(%d).\n", b->clusters_per_mft_record);
			goto not_ntfs;
		}
	}

	ntfs_log_debug("Checking clusters per index block.\n");
	if ((u8)b->clusters_per_index_record < 0xe1 ||
	    (u8)b->clusters_per_index_record > 0xf7) {
		switch (b->clusters_per_index_record) {
		case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
			break;
		default:
			ntfs_log_error("Unexpected clusters per index record "
				       "(%d).\n", b->clusters_per_index_record);
			goto not_ntfs;
		}
	}

	if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
		ntfs_log_debug("Warning: Bootsector has invalid end of sector "
			       "marker.\n");

	ntfs_log_debug("Bootsector check completed successfully.\n");

	ret = TRUE;
not_ntfs:
	return ret;
}
Exemple #23
0
/**
 * ntfs_df_array_fek_get
 */
static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array,
                                       ntfs_rsa_private_key rsa_key, char *thumbprint,
                                       int thumbprint_size)
{
    EFS_DF_HEADER *df_header;
    EFS_DF_CREDENTIAL_HEADER *df_cred;
    EFS_DF_CERT_THUMBPRINT_HEADER *df_cert;
    u8 *fek_buf;
    ntfs_fek *fek;
    u32 df_count, fek_size;
    unsigned i;

    df_count = le32_to_cpu(df_array->df_count);
    if (!df_count)
        ntfs_log_error("There are no elements in the DF array.\n");
    df_header = (EFS_DF_HEADER*)(df_array + 1);
    for (i = 0; i < df_count; i++, df_header = (EFS_DF_HEADER*)(
                (u8*)df_header + le32_to_cpu(df_header->df_length))) {
        df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)df_header +
                                              le32_to_cpu(df_header->cred_header_offset));
        if (df_cred->type != NTFS_CRED_TYPE_CERT_THUMBPRINT) {
            ntfs_log_debug("Credential type is not certificate "
                           "thumbprint, skipping DF entry.\n");
            continue;
        }
        df_cert = (EFS_DF_CERT_THUMBPRINT_HEADER*)((u8*)df_cred +
                  le32_to_cpu(
                      df_cred->cert_thumbprint_header_offset));
        if ((int)le32_to_cpu(df_cert->thumbprint_size)
                != thumbprint_size) {
            ntfs_log_error("Thumbprint size %d is not valid "
                           "(should be %d), skipping this DF "
                           "entry.\n",
                           le32_to_cpu(df_cert->thumbprint_size),
                           thumbprint_size);
            continue;
        }
        if (memcmp((u8*)df_cert +
                   le32_to_cpu(df_cert->thumbprint_offset),
                   thumbprint, thumbprint_size)) {
            ntfs_log_debug("Thumbprints do not match, skipping "
                           "this DF entry.\n");
            continue;
        }
        /*
         * The thumbprints match so this is probably the DF entry
         * matching the RSA key.  Try to decrypt the FEK with it.
         */
        fek_size = le32_to_cpu(df_header->fek_size);
        fek_buf = (u8*)df_header + le32_to_cpu(df_header->fek_offset);
        /* Decrypt the FEK.  Note: This is done in place. */
        fek_size = ntfs_raw_fek_decrypt(fek_buf, fek_size, rsa_key);
        if (fek_size) {
            /* Convert the FEK to our internal format. */
            fek = ntfs_fek_import_from_raw(fek_buf, fek_size);
            if (fek)
                return fek;
            ntfs_log_error("Failed to convert the decrypted file "
                           "encryption key to internal format.\n");
        } else
            ntfs_log_error("Failed to decrypt the file "
                           "encryption key.\n");
    }
    return NULL;
}
Exemple #24
0
/**
 * ntfs_ucstombs - convert a little endian Unicode string to a multibyte string
 * @ins:	input Unicode string buffer
 * @ins_len:	length of input string in Unicode characters
 * @outs:	on return contains the (allocated) output multibyte string
 * @outs_len:	length of output buffer in bytes
 *
 * Convert the input little endian, 2-byte Unicode string @ins, of length
 * @ins_len into the multibyte string format dictated by the current locale.
 *
 * If *@outs is NULL, the function allocates the string and the caller is
 * responsible for calling free(*@outs); when finished with it.
 *
 * On success the function returns the number of bytes written to the output
 * string *@outs (>= 0), not counting the terminating NULL byte. If the output
 * string buffer was allocated, *@outs is set to it.
 *
 * On error, -1 is returned, and errno is set to the error code. The following
 * error codes can be expected:
 *	EINVAL		Invalid arguments (e.g. @ins or @outs is NULL).
 *	EILSEQ		The input string cannot be represented as a multibyte
 *			sequence according to the current locale.
 *	ENAMETOOLONG	Destination buffer is too small for input string.
 *	ENOMEM		Not enough memory to allocate destination buffer.
 */
int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
		int outs_len)
{
	char *mbs;
	wchar_t wc;
	int i, o, mbs_len;
	int cnt = 0;
#ifdef HAVE_MBSINIT
	mbstate_t mbstate;
#endif

	if (!ins || !outs) {
		errno = EINVAL;
		return -1;
	}
	mbs = *outs;
	mbs_len = outs_len;
	if (mbs && !mbs_len) {
		errno = ENAMETOOLONG;
		return -1;
	}
	if (!mbs) {
		mbs_len = (ins_len + 1) * MB_CUR_MAX;
		mbs = (char*)malloc(mbs_len);
		if (!mbs)
			return -1;
	}
#ifdef HAVE_MBSINIT
	memset(&mbstate, 0, sizeof(mbstate));
#else
	wctomb(NULL, 0);
#endif
	for (i = o = 0; i < ins_len; i++) {
		/* Reallocate memory if necessary or abort. */
		if ((int)(o + MB_CUR_MAX) > mbs_len) {
			char *tc;
			if (mbs == *outs) {
				errno = ENAMETOOLONG;
				return -1;
			}
			tc = (char*)malloc((mbs_len + 64) & ~63);
			if (!tc)
				goto err_out;
			memcpy(tc, mbs, mbs_len);
			mbs_len = (mbs_len + 64) & ~63;
			free(mbs);
			mbs = tc;
		}
		/* Convert the LE Unicode character to a CPU wide character. */
		wc = (wchar_t)le16_to_cpu(ins[i]);
		if (!wc)
			break;
		/* Convert the CPU endian wide character to multibyte. */
#ifdef HAVE_MBSINIT
		cnt = wcrtomb(mbs + o, wc, &mbstate);
#else
		cnt = wctomb(mbs + o, wc);
#endif
		if (cnt == -1)
			goto err_out;
		if (cnt <= 0) {
			ntfs_log_debug("Eeek. cnt <= 0, cnt = %i\n", cnt);
			errno = EINVAL;
			goto err_out;
		}
		o += cnt;
	}
#ifdef HAVE_MBSINIT
	/* Make sure we are back in the initial state. */
	if (!mbsinit(&mbstate)) {
		ntfs_log_debug("Eeek. mbstate not in initial state!\n");
		errno = EILSEQ;
		goto err_out;
	}
#endif
	/* Now write the NULL character. */
	mbs[o] = '\0';
	if (*outs != mbs)
		*outs = mbs;
	return o;
err_out:
	if (mbs != *outs) {
		int eo = errno;
		free(mbs);
		errno = eo;
	}
	return -1;
}
Exemple #25
0
/*
 * ntfs_names_full_collate() fully collate two Unicode names
 *
 * @name1:	first Unicode name to compare
 * @name1_len:	length of first Unicode name to compare
 * @name2:	second Unicode name to compare
 * @name2_len:	length of second Unicode name to compare
 * @ic:		either CASE_SENSITIVE or IGNORE_CASE
 * @upcase:	upcase table (ignored if @ic is CASE_SENSITIVE)
 * @upcase_len:	upcase table size (ignored if @ic is CASE_SENSITIVE)
 *
 *  -1 if the first name collates before the second one,
 *   0 if the names match,
 *   1 if the second name collates before the first one, or
 *
 */
int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
		const ntfschar *name2, const u32 name2_len,
		const IGNORE_CASE_BOOL ic, const ntfschar *upcase,
		const u32 upcase_len)
{
	u32 cnt;
	u16 c1, c2;
	u16 u1, u2;

#ifdef DEBUG
	if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) {
		ntfs_log_debug("ntfs_names_collate received NULL pointer!\n");
		exit(1);
	}
#endif
	cnt = min(name1_len, name2_len);
	if (cnt > 0) {
		if (ic == CASE_SENSITIVE) {
			while (--cnt && (*name1 == *name2)) {
				name1++;
				name2++;
			}
			u1 = c1 = le16_to_cpu(*name1);
			u2 = c2 = le16_to_cpu(*name2);
			if (u1 < upcase_len)
				u1 = le16_to_cpu(upcase[u1]);
			if (u2 < upcase_len)
				u2 = le16_to_cpu(upcase[u2]);
			if ((u1 == u2) && cnt)
				do {
					name1++;
					u1 = le16_to_cpu(*name1);
					name2++;
					u2 = le16_to_cpu(*name2);
					if (u1 < upcase_len)
						u1 = le16_to_cpu(upcase[u1]);
					if (u2 < upcase_len)
						u2 = le16_to_cpu(upcase[u2]);
				} while ((u1 == u2) && --cnt);
			if (u1 < u2)
				return -1;
			if (u1 > u2)
				return 1;
			if (name1_len < name2_len)
				return -1;
			if (name1_len > name2_len)
				return 1;
			if (c1 < c2)
				return -1;
			if (c1 > c2)
				return 1;
		} else {
			do {
				u1 = c1 = le16_to_cpu(*name1);
				name1++;
				u2 = c2 = le16_to_cpu(*name2);
				name2++;
				if (u1 < upcase_len)
					u1 = le16_to_cpu(upcase[u1]);
				if (u2 < upcase_len)
					u2 = le16_to_cpu(upcase[u2]);
			} while ((u1 == u2) && --cnt);
			if (u1 < u2)
				return -1;
			if (u1 > u2)
				return 1;
			if (name1_len < name2_len)
				return -1;
			if (name1_len > name2_len)
				return 1;
		}
	} else {
		if (name1_len < name2_len)
			return -1;
		if (name1_len > name2_len)
			return 1;
	}
	return 0;
}
Exemple #26
0
bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags)
{
    ntfs_vd *vd = NULL;
    gekko_fd *fd = NULL;

    // Sanity check
    if (!name || !interface) {
        errno = EINVAL;
        return -1;
    }

    // Initialise ntfs-3g
    ntfsInit();

    // Check that the requested mount name is free
    if (ntfsGetDevice(name, false)) {
        errno = EADDRINUSE;
        return false;
    }

    // Check that we can at least read from this device
    if (!(interface->features & FEATURE_MEDIUM_CANREAD)) {
        errno = EPERM;
        return false;
    }

    // Allocate the volume descriptor
    vd = (ntfs_vd*)ntfs_alloc(sizeof(ntfs_vd));
    if (!vd) {
        errno = ENOMEM;
        return false;
    }

    // Setup the volume descriptor
    vd->id = interface->ioType;
    vd->flags = 0;
    vd->uid = 0;
    vd->gid = 0;
    vd->fmask = 0;
    vd->dmask = 0;
    vd->atime = ((flags & NTFS_UPDATE_ACCESS_TIMES) ? ATIME_ENABLED : ATIME_DISABLED);
    vd->showHiddenFiles = (flags & NTFS_SHOW_HIDDEN_FILES);
    vd->showSystemFiles = (flags & NTFS_SHOW_SYSTEM_FILES);

    // Allocate the device driver descriptor
    fd = (gekko_fd*)ntfs_alloc(sizeof(gekko_fd));
    if (!fd) {
        ntfs_free(vd);
        errno = ENOMEM;
        return false;
    }

    // Setup the device driver descriptor
    fd->interface = interface;
    fd->startSector = startSector;
    fd->sectorSize = 0;
    fd->sectorCount = 0;
    fd->cachePageCount = cachePageCount;
    fd->cachePageSize = cachePageSize;

    // Allocate the device driver
    vd->dev = ntfs_device_alloc(name, 0, &ntfs_device_gekko_io_ops, fd);
    if (!vd->dev) {
        ntfs_free(fd);
        ntfs_free(vd);
        return false;
    }

    // Build the mount flags
    if (flags & NTFS_READ_ONLY)
        vd->flags |= MS_RDONLY;
    else
    {
        if (!(interface->features & FEATURE_MEDIUM_CANWRITE))
            vd->flags |= MS_RDONLY;
        if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
            vd->flags |= MS_EXCLUSIVE;
    }
    if (flags & NTFS_RECOVER)
        vd->flags |= MS_RECOVER;
    if (flags & NTFS_IGNORE_HIBERFILE)
        vd->flags |= MS_IGNORE_HIBERFILE;

    if (vd->flags & MS_RDONLY)
        ntfs_log_debug("Mounting \"%s\" as read-only\n", name);

    // Mount the device
    vd->vol = ntfs_device_mount(vd->dev, vd->flags);
    if (!vd->vol) {
        switch(ntfs_volume_error(errno)) {
        case NTFS_VOLUME_NOT_NTFS:
            errno = EINVALPART;
            break;
        case NTFS_VOLUME_CORRUPT:
            errno = EINVALPART;
            break;
        case NTFS_VOLUME_HIBERNATED:
            errno = EHIBERNATED;
            break;
        case NTFS_VOLUME_UNCLEAN_UNMOUNT:
            errno = EDIRTY;
            break;
        default:
            errno = EINVAL;
            break;
        }
        ntfs_device_free(vd->dev);
        ntfs_free(vd);
        return false;
    }

    // Initialise the volume descriptor
    if (ntfsInitVolume(vd)) {
        ntfs_umount(vd->vol, true);
        ntfs_free(vd);
        return false;
    }

    // Add the device to the devoptab table
    if (ntfsAddDevice(name, vd)) {
        ntfsDeinitVolume(vd);
        ntfs_umount(vd->vol, true);
        ntfs_free(vd);
        return false;
    }

    return true;
}
Exemple #27
0
int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
{
    MASTER_BOOT_RECORD mbr;
    PARTITION_RECORD *partition = NULL;
    sec_t partition_starts[NTFS_MAX_PARTITIONS] = {0};
    int partition_count = 0;
    sec_t part_lba = 0;
    int i;

    union {
        u8 buffer[BYTES_PER_SECTOR];
        MASTER_BOOT_RECORD mbr;
        EXTENDED_BOOT_RECORD ebr;
        NTFS_BOOT_SECTOR boot;
    } sector;

    // Sanity check
    if (!interface) {
        errno = EINVAL;
        return -1;
    }
    if (!partitions)
        return 0;

    // Initialise ntfs-3g
    ntfsInit();

    // Start the device and check that it is inserted
    if (!interface->startup()) {
        errno = EIO;
        return -1;
    }
    if (!interface->isInserted()) {
        return 0;
    }

    // Read the first sector on the device
    if (!interface->readSectors(0, 1, &sector.buffer)) {
        errno = EIO;
        return -1;
    }

    // If this is the devices master boot record
    if (sector.mbr.signature == MBR_SIGNATURE) {
        memcpy(&mbr, &sector, sizeof(MASTER_BOOT_RECORD));
        ntfs_log_debug("Valid Master Boot Record found\n");

        // Search the partition table for all NTFS partitions (max. 4 primary partitions)
        for (i = 0; i < 4; i++) {
            partition = &mbr.partitions[i];
            part_lba = le32_to_cpu(mbr.partitions[i].lba_start);

            ntfs_log_debug("Partition %i: %s, sector %d, type 0x%x\n", i + 1,
                           partition->status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
                           part_lba, partition->type);

            // Figure out what type of partition this is
            switch (partition->type) {

            // Ignore empty partitions
            case PARTITION_TYPE_EMPTY:
                continue;

            // NTFS partition
            case PARTITION_TYPE_NTFS: {
                ntfs_log_debug("Partition %i: Claims to be NTFS\n", i + 1);

                // Read and validate the NTFS partition
                if (interface->readSectors(part_lba, 1, &sector)) {
                    if (sector.boot.oem_id == NTFS_OEM_ID) {
                        ntfs_log_debug("Partition %i: Valid NTFS boot sector found\n", i + 1);
                        if (partition_count < NTFS_MAX_PARTITIONS) {
                            partition_starts[partition_count] = part_lba;
                            partition_count++;
                        }
                    } else {
                        ntfs_log_debug("Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1);
                    }
                }

                break;

            }

            // DOS 3.3+ or Windows 95 extended partition
            case PARTITION_TYPE_DOS33_EXTENDED:
            case PARTITION_TYPE_WIN95_EXTENDED: {
                ntfs_log_debug("Partition %i: Claims to be Extended\n", i + 1);

                // Walk the extended partition chain, finding all NTFS partitions within it
                sec_t ebr_lba = part_lba;
                sec_t next_erb_lba = 0;
                do {

                    // Read and validate the extended boot record
                    if (interface->readSectors(ebr_lba + next_erb_lba, 1, &sector)) {
                        if (sector.ebr.signature == EBR_SIGNATURE) {
                            ntfs_log_debug("Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
                                           sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
                                           sector.ebr.partition.type);

                            // Get the start sector of the current partition
                            // and the next extended boot record in the chain
                            part_lba = ebr_lba + next_erb_lba + le32_to_cpu(sector.ebr.partition.lba_start);
                            next_erb_lba = le32_to_cpu(sector.ebr.next_ebr.lba_start);

                            // Check if this partition has a valid NTFS boot record
                            if (interface->readSectors(part_lba, 1, &sector)) {
                                if (sector.boot.oem_id == NTFS_OEM_ID) {
                                    ntfs_log_debug("Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba);
                                    if(sector.ebr.partition.type != PARTITION_TYPE_NTFS) {
                                        ntfs_log_warning("Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n", part_lba, sector.ebr.partition.type, PARTITION_TYPE_NTFS);
                                    }
                                    if (partition_count < NTFS_MAX_PARTITIONS) {
                                        partition_starts[partition_count] = part_lba;
                                        partition_count++;
                                    }
                                }
                            }

                        } else {
                            next_erb_lba = 0;
                        }
                    }

                } while (next_erb_lba);

                break;

            }

            // Unknown or unsupported partition type
            default: {

                // Check if this partition has a valid NTFS boot record anyway,
                // it might be misrepresented due to a lazy partition editor
                if (interface->readSectors(part_lba, 1, &sector)) {
                    if (sector.boot.oem_id == NTFS_OEM_ID) {
                        ntfs_log_debug("Partition %i: Valid NTFS boot sector found\n", i + 1);
                        if(partition->type != PARTITION_TYPE_NTFS) {
                            ntfs_log_warning("Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n", i + 1, partition->type, PARTITION_TYPE_NTFS);
                        }
                        if (partition_count < NTFS_MAX_PARTITIONS) {
                            partition_starts[partition_count] = part_lba;
                            partition_count++;
                        }
                    }
                }

                break;

            }

            }

        }

        // Else it is assumed this device has no master boot record
    } else {
        ntfs_log_debug("No Master Boot Record was found!\n");

        // As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
        for (i = 0; i < 64; i++) {
            if (interface->readSectors(i, 1, &sector)) {
                if (sector.boot.oem_id == NTFS_OEM_ID) {
                    ntfs_log_debug("Valid NTFS boot sector found at sector %d!\n", i);
                    if (partition_count < NTFS_MAX_PARTITIONS) {
                        partition_starts[partition_count] = i;
                        partition_count++;
                    }
                }
            }
        }

    }

    // Shutdown the device
    /*interface->shutdown();*/

    // Return the found partitions (if any)
    if (partition_count > 0) {
        *partitions = (sec_t*)ntfs_alloc(sizeof(sec_t) * partition_count);
        if (*partitions) {
            memcpy(*partitions, &partition_starts, sizeof(sec_t) * partition_count);
            return partition_count;
        }
    }

    return 0;
}
Exemple #28
0
/**
 * ntfs_boot_sector_is_ntfs - check if buffer contains a valid ntfs boot sector
 * @b:		buffer containing putative boot sector to analyze
 * @silent:	if zero, output progress messages to stderr
 *
 * Check if the buffer @b contains a valid ntfs boot sector. The buffer @b
 * must be at least 512 bytes in size.
 *
 * If @silent is zero, output progress messages to stderr. Otherwise, do not
 * output any messages (except when configured with --enable-debug in which
 * case warning/debug messages may be displayed).
 *
 * Return TRUE if @b contains a valid ntfs boot sector and FALSE if not.
 */
BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, const BOOL silent __attribute__((unused)))
{
	u32 i;

	ntfs_log_debug("\nBeginning bootsector check...\n");

	/* Calculate the checksum. Note, this is just a simple addition of
	   all u32 values in the bootsector starting at the beginning and
	   finishing at the offset of the checksum itself (i.e. not including
	   the checksum...). */
	if ((void*)b < (void*)&b->checksum) {
		u32 *u = (u32 *)b;
		u32 *bi = (u32 *)(&b->checksum);

		ntfs_log_debug("Calculating bootsector checksum... ");

		for (i = 0; u < bi; ++u)
			i += le32_to_cpup(u);

		if (le32_to_cpu(b->checksum) && le32_to_cpu(b->checksum) != i)
			goto not_ntfs;
		ntfs_log_debug("OK\n");
	}

	/* Check OEMidentifier is "NTFS    " */
	ntfs_log_debug("Checking OEMid... ");
	if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) /* "NTFS    " */
		goto not_ntfs;
	ntfs_log_debug("OK\n");

	/* Check bytes per sector value is between 256 and 4096. */
	ntfs_log_debug("Checking bytes per sector... ");
	if (le16_to_cpu(b->bpb.bytes_per_sector) <  0x100 ||
	    le16_to_cpu(b->bpb.bytes_per_sector) > 0x1000)
		goto not_ntfs;
	ntfs_log_debug("OK\n");

	/* Check sectors per cluster value is valid. */
	ntfs_log_debug("Checking sectors per cluster... ");
	switch (b->bpb.sectors_per_cluster) {
	case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
		break;
	default:
		goto not_ntfs;
	}
	ntfs_log_debug("OK\n");

	/* Check the cluster size is not above 65536 bytes. */
	ntfs_log_debug("Checking cluster size... ");
	if ((u32)le16_to_cpu(b->bpb.bytes_per_sector) *
	    b->bpb.sectors_per_cluster > 0x10000)
		goto not_ntfs;
	ntfs_log_debug("OK\n");

	/* Check reserved/unused fields are really zero. */
	ntfs_log_debug("Checking reserved fields are zero... ");
	if (le16_to_cpu(b->bpb.reserved_sectors) ||
	    le16_to_cpu(b->bpb.root_entries) ||
	    le16_to_cpu(b->bpb.sectors) ||
	    le16_to_cpu(b->bpb.sectors_per_fat) ||
	    le32_to_cpu(b->bpb.large_sectors) ||
	    b->bpb.fats)
		goto not_ntfs;
	ntfs_log_debug("OK\n");

	/* Check clusters per file mft record value is valid. */
	ntfs_log_debug("Checking clusters per mft record... ");
	if ((u8)b->clusters_per_mft_record < 0xe1 ||
	    (u8)b->clusters_per_mft_record > 0xf7) {
		switch (b->clusters_per_mft_record) {
		case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
			break;
		default:
			goto not_ntfs;
		}
	}
	ntfs_log_debug("OK\n");

	/* Check clusters per index block value is valid. */
	ntfs_log_debug("Checking clusters per index block... ");
	if ((u8)b->clusters_per_index_record < 0xe1 ||
	    (u8)b->clusters_per_index_record > 0xf7) {
		switch (b->clusters_per_index_record) {
		case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
			break;
		default:
			goto not_ntfs;
		}
	}
	ntfs_log_debug("OK\n");

	if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
		ntfs_log_debug("Warning: Bootsector has invalid end of sector marker.\n");

	ntfs_log_debug("Bootsector check completed successfully.\n");

	return TRUE;
not_ntfs:
	ntfs_log_debug("FAILED\n");
	ntfs_log_debug("Bootsector check failed.  Aborting...\n");
	return FALSE;
}