testdisk/src/ntfs_utl.c
2009-03-22 14:55:20 +01:00

196 lines
5.7 KiB
C

/**
* ntfs_utl.c - Part of the TestDisk project.
*
* Copyright (c) 2004-2007 Christophe Grenier
*
* Original version comes from the Linux-NTFS project.
* Copyright (c) 2003 Lode Leroy
* Copyright (c) 2003 Anton Altaparmakov
* Copyright (c) 2003 Richard Russon
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_LIBNTFS
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <errno.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_MACHINE_ENDIAN_H
#include <machine/endian.h>
#endif
#include <stdarg.h>
#include "types.h"
#include <ntfs/attrib.h>
#include "ntfs_utl.h"
#include "common.h"
#include "log.h"
/**
* find_attribute - Find an attribute of the given type
* @type: An attribute type, e.g. AT_FILE_NAME
* @ctx: A search context, created using ntfs_get_attr_search_ctx
*
* Using the search context to keep track, find the first/next occurrence of a
* given attribute type.
*
* N.B. This will return a pointer into @mft. As long as the search context
* has been created without an inode, it won't overflow the buffer.
*
* Return: Pointer Success, an attribute was found
* NULL Error, no matching attributes were found
*/
ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx)
{
if (!ctx) {
errno = EINVAL;
return NULL;
}
if (ntfs_attr_lookup(type, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx) != 0) {
#ifdef DEBUG_NTFS
log_debug("find_attribute didn't find an attribute of type: 0x%02x.\n", type);
#endif
return NULL; /* None / no more of that type */
}
#ifdef DEBUG_NTFS
log_debug("find_attribute found an attribute of type: 0x%02x.\n", type);
#endif
return ctx->attr;
}
/**
* find_first_attribute - Find the first attribute of a given type
* @type: An attribute type, e.g. AT_FILE_NAME
* @mft: A buffer containing a raw MFT record
*
* Search through a raw MFT record for an attribute of a given type.
* The return value is a pointer into the MFT record that was supplied.
*
* N.B. This will return a pointer into @mft. The pointer won't stray outside
* the buffer, since we created the search context without an inode.
*
* Return: Pointer Success, an attribute was found
* NULL Error, no matching attributes were found
*/
ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft)
{
ntfs_attr_search_ctx *ctx;
ATTR_RECORD *rec;
if (!mft) {
errno = EINVAL;
return NULL;
}
ctx = ntfs_attr_get_search_ctx(NULL, mft);
if (!ctx) {
log_error("Couldn't create a search context.\n");
return NULL;
}
rec = find_attribute(type, ctx);
ntfs_attr_put_search_ctx(ctx);
#ifdef DEBUG_NTFS
if (rec)
log_debug("find_first_attribute: found attr of type 0x%02x.\n", type);
else
log_debug("find_first_attribute: didn't find attr of type 0x%02x.\n", type);
#endif
return rec;
}
/**
* utils_cluster_in_use - Determine if a cluster is in use
* @vol: An ntfs volume obtained from ntfs_mount
* @lcn: The Logical Cluster Number to test
*
* The metadata file $Bitmap has one binary bit representing each cluster on
* disk. The bit will be set for each cluster that is in use. The function
* reads the relevant part of $Bitmap into a buffer and tests the bit.
*
* This function has a static buffer in which it caches a section of $Bitmap.
* If the lcn, being tested, lies outside the range, the buffer will be
* refreshed.
*
* Return: 1 Cluster is in use
* 0 Cluster is free space
* -1 Error occurred
*/
int utils_cluster_in_use(ntfs_volume *vol, long long lcn)
{
static unsigned char buffer[512];
static long long bmplcn = -sizeof(buffer) - 1; /* Which bit of $Bitmap is in the buffer */
int byte, bit;
if (!vol) {
errno = EINVAL;
return -1;
}
/* Does lcn lie in the section of $Bitmap we already have cached? */
if ((bmplcn <0 ) ||(lcn < (unsigned)bmplcn) || (lcn >= ((unsigned)bmplcn + ((unsigned)sizeof(buffer) << 3)))) {
ntfs_attr *attr;
#ifdef DEBUG_NTFS
log_debug("Bit lies outside cache.\n");
#endif
attr = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
if (!attr) {
log_error("Couldn't open $Bitmap\n");
return -1;
}
/* Mark the buffer as in use, in case the read is shorter. */
memset(buffer, 0xFF, sizeof(buffer));
bmplcn = lcn & (~((sizeof(buffer) << 3) - 1));
if (ntfs_attr_pread(attr, (bmplcn>>3), sizeof(buffer), buffer) < 0) {
log_error("Couldn't read $Bitmap\n");
ntfs_attr_close(attr);
return -1;
}
#ifdef DEBUG_NTFS
log_debug("Reloaded bitmap buffer.\n");
#endif
ntfs_attr_close(attr);
}
bit = 1 << (lcn & 7);
byte = (lcn >> 3) & (sizeof(buffer) - 1);
#ifdef DEBUG_NTFS
log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] & bit);
#endif
return (buffer[byte] & bit);
}
#endif