Changes by: flatcap
Update of /cvsroot/linux-ntfs/linux-ntfs/ntfstools
In directory usw-pr-cvs1:/tmp/cvs-serv7335
Added Files:
ldm.c
Log Message:
Dump the LDM (Logical Disk Manager) Database
--- NEW FILE ---
/*
* $Id: ldm.c,v 1.1 2001/06/03 00:21:06 flatcap Exp $
*
* ldm - Part of the Linux-NTFS project.
*
* Copyright (c) 2001 Richard Russon.
*
* This utility will interpret the Logical Disk Manager Database and
* display the results on stdout.
*
* Richard Russon <nt...@fl...>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS source
* in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <asm/byteorder.h>
#include <time.h>
#include <string.h>
#define __u64 unsigned long long
#define __u32 unsigned long
#define __u16 unsigned short
#define __u8 unsigned char
#define SWAB16(x) (__u16) __arch__swab16 (*((__u16 *) (x)))
#define SWAB32(x) (__u32) __arch__swab32 (*((__u32 *) (x)))
#define SWAB64(x) (__u64) __arch__swab64 (*((__u64 *) (x)))
#define MAGIC_VMDB 0x42444d56 /* "VMDB" */
#define MAGIC_VBLK 0x4b4c4256 /* "VBLK" */
#define MAGIC_PRIVHEAD 0x4441454856495250 /* "PRIVHEAD" */
#define MAGIC_TOCBLOCK 0x4b434f4c42434f54 /* "TOCBLOCK" */
#define VBLK_COMP 0x32 /* Component */
#define VBLK_PART 0x33 /* Partition */
#define VBLK_DISK 0x34 /* Disk */
#define VBLK_DGRP 0x45 /* Disk Group */
#define VBLK_VOLU 0x51 /* Volume */
char * print_guid (__u8 *block)
{
static char buffer[40];
memset (buffer, 0, sizeof (buffer));
if (block)
{
sprintf (buffer, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
block[0], block[1], block[2], block[3], block[4], block[5], block[6], block[7],
block[8], block[9], block[10], block[11], block[12], block[13], block[14], block[15]);
}
return buffer;
}
char * print_time (__u64 t)
{
static char buffer[32];
__u32 unix_utc;
struct tm *time;
t /= 10000000;
unix_utc = t - ((__u64) 369*365+89)*24*3600;
time = localtime(&unix_utc);
sprintf (buffer, "%02d/%02d/%04d %02d:%02d", time->tm_mday, time->tm_mon+1, time->tm_year+1900, time->tm_hour, time->tm_min);
return buffer;
}
/* Get a variable-width number
* The width is stored in a byte before the number
*/
__u64 get_vnum (__u8 *block)
{
__u64 value = 0;
int length = 0;
int i;
if (!block)
return 0;
length = block[0];
if (length > 8)
return 0;
for (i = 1; i <= length; i++)
{
value <<= 8;
value += block[i];
}
return value;
}
/* Extract a non-null-terminated ASCII string.
* The length is stored in a byte before the string
*/
__u8 * get_vstr (__u8 *block)
{
static __u8 buffer[256];
int length = 0;
memset (buffer, 0, sizeof (buffer));
if (block)
{
length = block[0];
memcpy (buffer, block+1, length);
}
return buffer;
}
void dump_component (__u8 *block, int size)
{
int rel_objid;
int rel_name;
int rel_vstate;
int rel_parent;
if (!block)
return;
/* Calculate relative offsets */
rel_objid = 1 + block[0x18];
rel_name = 1 + block[0x18+rel_objid] + rel_objid;
rel_vstate = 1 + block[0x18+rel_name] + rel_name;
rel_parent = 1 + block[0x18+rel_vstate] + rel_vstate;
printf ("0x%06lX: [%06lX] <Component>\n", SWAB32 (block+0x04), SWAB32 (block+0x08));
printf (" Name : %s\n", get_vstr (block+0x18+rel_objid));
printf (" Object Id : 0x%04llx\n", get_vnum (block+0x18));
printf (" Parent Id : 0x%04llx\n", get_vnum (block+0x2F+rel_vstate));
}
void dump_partition (__u8 *block, int size)
{
__u64 temp;
int rel_objid;
int rel_name;
int rel_size;
int rel_parent;
int rel_diskid;
if (!block)
return;
/* Calculate relative offsets */
rel_objid = 1 + block[0x18];
rel_name = 1 + block[0x18+rel_objid] + rel_objid;
rel_size = 1 + block[0x34+rel_name] + rel_name;
rel_parent = 1 + block[0x34+rel_size] + rel_size;
rel_diskid = 1 + block[0x34+rel_parent] + rel_parent;
printf ("0x%06lX: [%06lX] <Partition>\n", SWAB32 (block+0x04), SWAB32 (block+0x08));
printf (" Name : %s\n", get_vstr (block+0x18+rel_objid));
printf (" Object Id : 0x%04llx\n", get_vnum (block+0x18));
printf (" Parent Id : 0x%04llx\n", get_vnum (block+0x34+rel_size));
printf (" Disk Id : 0x%04llx\n", get_vnum (block+0x34+rel_parent));
printf (" Start : 0x%llX\n", SWAB64 (block+0x24+rel_name));
temp = get_vnum (block+0x34+rel_name);
printf (" Size : 0x%llX (%lld MB)\n", temp, temp >> 11);
temp = SWAB64 (block+0x2C+rel_name);
printf (" Volume Off : 0x%llX (%llu MB)\n", temp, temp >> 11);
}
void dump_disk (__u8 *block, int size)
{
int rel_objid;
int rel_name;
int rel_diskid;
if (!block)
return;
/* Calculate relative offsets */
rel_objid = 1 + block[0x18];
rel_name = 1 + block[0x18+rel_objid] + rel_objid;
rel_diskid = 1 + block[0x18+rel_name] + rel_name;
printf ("0x%06lX: [%06lX] <Disk>\n", SWAB32 (block+0x04), SWAB32 (block+0x08));
printf (" Name : %s\n", get_vstr (block+0x18+rel_objid));
printf (" Object Id : 0x%04llx\n", get_vnum (block+0x18));
printf (" Disk Id : %s\n", get_vstr (block+0x18+rel_name));
/* need another example to test
if (block[0x18+rel_name])
{
printf (" AltName : %s\n", get_vstr (block+29));
}
*/
}
void dump_diskgroup (__u8 *block, int size)
{
int rel_objid;
int rel_name;
int rel_diskid;
if (!block)
return;
/* Calculate relative offsets */
rel_objid = 1 + block[0x18];
rel_name = 1 + block[0x18+rel_objid] + rel_objid;
rel_diskid = 1 + block[0x18+rel_name] + rel_name;
printf ("0x%06lX: [%06lX] <DiskGroup>\n", SWAB32 (block+0x04), SWAB32 (block+0x08));
printf (" Name : %s\n", get_vstr (block+0x18+rel_objid));
printf (" Object Id : 0x%04llx\n", get_vnum (block+0x18));
printf (" GUID : %s\n", print_guid (block+0x18+rel_name));
}
void dump_volume (__u8 *block, int size)
{
__u64 temp;
int rel_objid;
int rel_name;
int rel_vtype;
int rel_size;
int rel_drive;
if (!block)
return;
/* Calculate relative offsets */
rel_objid = 1 + block[0x18];
rel_name = 1 + block[0x18+rel_objid] + rel_objid;
rel_vtype = 1 + block[0x18+rel_name] + rel_name;
rel_size = 1 + block[0x40+rel_vtype] + rel_vtype;
rel_drive = 1 + block[0x55+rel_size] + rel_size;
printf ("0x%06lX: [%06lX] <Volume>\n", SWAB32 (block+0x04), SWAB32 (block+0x08));
printf (" Name : %s\n", get_vstr (block+0x18+rel_objid));
printf (" Object Id : 0x%04llx\n", get_vnum (block+0x18));
printf (" Volume state: %s\n", block+0x19+rel_vtype);
temp = get_vnum (block+0x40+rel_vtype);
printf (" Size : 0x%08llX (%lld MB)\n", temp, temp >> 11);
printf (" GUID : %s\n", print_guid (block+0x45+rel_size));
/* GUID (Reg) Order F,E,D,C,B,A,9,8,6,7,4,5,3,2,1,0 (8-2-2-4) WHY??? */
printf (" GUID (Reg) : %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
block[rel_size+0x54], block[rel_size+0x53], block[rel_size+0x52], block[rel_size+0x51], block[rel_size+0x50], block[rel_size+0x4F], block[rel_size+0x4E], block[rel_size+0x4D],
block[rel_size+0x4B], block[rel_size+0x4C], block[rel_size+0x49], block[rel_size+0x4A], block[rel_size+0x45], block[rel_size+0x46], block[rel_size+0x47], block[rel_size+0x48]);
if (block[0x55+rel_size] != 0)
{
printf (" Drive Hint : %s\n", get_vstr (block+0x55+rel_size));
}
}
int dump_vmdb (__u8 *block)
{
__u32 temp = 0;
int vblocks = 0;
int vbsize = 0;
int hsize = 0;
int recsize = 0;
int i;
if (!block)
return 1;
temp = *((__u32*) block);
if (MAGIC_VMDB != temp)
{
printf ("not a VMDB\n");
return 1;
}
printf ("VMDB DATABASE HEADER:\n");
vblocks = SWAB32 (block+4);
vbsize = SWAB32 (block+8);
hsize = SWAB32 (block+12);
printf ("Signature : %c%c%c%c\n", block[0], block[1], block[2], block[3]);
printf ("Flags : 0x%X\n", SWAB16 (block+16));
printf ("Timestamp : %s\n", print_time (SWAB64 (block+189)));
printf ("Block size : %d bytes\n", vbsize);
printf ("Header size : %d bytes\n", hsize);
printf ("Version : %d/%d\n", SWAB16 (block+18), SWAB16 (block+20));
printf ("Number of VBLKs : 0x%X\n", vblocks);
printf ("Disk Group Name : %s\n", block+22);
printf ("Disk Group Id : %s\n", block+53);
printf ("Committed Sequence : 0x%llX\n", SWAB64 (block+117));
printf ("Pending Sequence : 0x%llX\n", SWAB64 (block+125));
#if 0
printf ("Unknowns : 0x%08X 0x%08X 0x%08X 0x%08X\n", SWAB32 (block+133), SWAB32 (block+141), SWAB32 (block+149), SWAB32 (block+157));
#endif
printf ("\n");
printf ("VBLK DATABASE:\n");
block += hsize;
for (i = 0; i < vblocks; i++, block += vbsize)
{
temp = *((__u32*) block);
if (MAGIC_VBLK != temp)
{
/*printf ("%d not a VBLK\n", i);*/
/*the last four are missing*/
break;
}
recsize = SWAB16 (block+14) * vbsize;
if (recsize == 0)
continue;
switch (block[19])
{
/* add a recsize param? */
case VBLK_COMP: dump_component (block, vbsize); break;
case VBLK_PART: dump_partition (block, vbsize); break;
case VBLK_DISK: dump_disk (block, vbsize); break;
case VBLK_DGRP: dump_diskgroup (block, vbsize); break;
case VBLK_VOLU: dump_volume (block, vbsize); break;
default: continue; /* extended here? */
}
printf ("\n");
if (recsize > vbsize)
block += recsize - vbsize; /* skip extension record */
}
return 0;
}
int dump_privhead (__u8 *block)
{
__u64 temp = 0;
if (!block)
{
return 1;
}
temp = *((__u64*) block);
if (MAGIC_PRIVHEAD != temp)
{
printf ("Not a PRIVHEAD\n");
return 1;
}
printf ("PRIVATE HEAD:\n");
printf ("Signature : %c%c%c%c%c%c%c%c\n", block[0], block[1], block[2], block[3], block[4], block[5], block[6], block[7]);
printf ("Version : %d.%d\n", SWAB16 (block + 12), SWAB16 (block + 14));
if (block[48])
printf ("Disk Id : %s\n", block+48);
if (block[112])
printf ("Host Id : %s\n", block+112);
if (block[176])
printf ("Disk Group Id : %s\n", block+176);
printf ("Disk Group Name : %s\n", block+240);
printf ("Logical disk start : 0x%llX\n", SWAB64 (block+283));
temp = SWAB64 (block+291);
printf ("Logical disk size : 0x%llX (%lld MB)\n", temp, temp>>11);
printf ("Configuration start: 0x%llX\n", SWAB64 (block+299));
temp = SWAB64 (block+307);
printf ("Configuration size : 0x%llX (%lld MB)\n", temp, temp>>11);
printf ("Number of TOCs : %lld\n", SWAB64 (block+315));
printf ("TOC size : 0x%llX\n", SWAB64 (block+323));
printf ("Number of Configs : %ld\n", SWAB32 (block+331));
printf ("Config size : 0x%llX bytes\n", SWAB64 (block+339));
printf ("Number of Logs : %ld\n", SWAB32 (block+335));
printf ("Log size : 0x%llX bytes\n", SWAB64 (block+347));
#if 0
/* not in orig version */
printf ("-------------------:\n");
printf ("Timestamp : %s\n", print_time (SWAB64 (block+16)));
printf ("disk id : 0x%lX (of something?)\n", SWAB32 (block+355));
printf ("GUID of disk set : %s\n", print_guid (block+359));
printf ("GUID of disk set : %s\n", print_guid (block+375));
#endif
printf ("\n");
return 0;
}
int dump_tocblock (__u8 *block)
{
__u64 temp = 0;
int i;
if (!block)
{
return 1;
}
temp = *((__u64*) block);
if (MAGIC_TOCBLOCK != temp)
{
printf ("Not a TOCBLOCK\n");
return 1;
}
for (i = 0; i < 2; i++)
{
printf ("TOC %d:\n", i);
printf ("Signature : %c%c%c%c%c%c%c%c\n", block[0], block[1], block[2], block[3], block[4], block[5], block[6], block[7]);
/* sequence could be 64 bits */
printf ("Sequence : 0x%llX\n", SWAB64 (block+12));
#if 0
printf ("Bitmap name : \"%s\"\n", block+36);
#endif
printf ("Config bitmap start: 0x%llX\n", SWAB64 (block+46));
printf ("Config bitmap size : 0x%llX\n", SWAB64 (block+54));
#if 0
printf ("Bitmap name : \"%s\"\n", block+70);
#endif
printf ("Log bitmap start : 0x%llX\n", SWAB64 (block+80));
printf ("Log bitmap size : 0x%llX\n", SWAB64 (block+88));
}
printf ("\n");
return 0;
}
/* Yay! O(n^2) */
int dump_disks (__u8 *block)
{
__u64 temp;
int vblocks;
int vbsize;
int i;
int j;
__u8 *ioff;
__u8 *joff;
if (!block)
return 1;
if (MAGIC_VMDB != *((__u32*) block))
{
printf ("not a VMDB\n");
return 1;
}
printf ("PARTITION LAYOUT:\n");
printf ("\n");
vblocks = SWAB32 (block+4);
vbsize = SWAB32 (block+8);
for (i = 4; i < vblocks; i++) /* Skip the VMDB header */
{
int diskid;
int parent;
int rel_objid;
ioff = block + i*vbsize;
if (MAGIC_VBLK != *((__u32*) ioff))
break;
if (VBLK_DISK != ioff[19])
continue;
/* Calculate relative offsets */
rel_objid = 1 + ioff[0x18];
printf ("Disk %s:\n", get_vstr (ioff+0x18+rel_objid));
diskid = get_vnum (ioff+0x18);
for (j = 4; j < vblocks; j++)
{
int rel_objid;
int rel_name;
int rel_size;
int rel_parent;
joff = block + j*vbsize;
if (MAGIC_VBLK != *((__u32*) joff))
break;
if (VBLK_PART != joff[19])
continue;
/* Calculate relative offsets */
rel_objid = 1 + joff[0x18];
rel_name = 1 + joff[0x18+rel_objid] + rel_objid;
rel_size = 1 + joff[0x34+rel_name] + rel_name;
rel_parent = 1 + joff[0x34+rel_size] + rel_size;
parent = get_vnum (joff+0x34+rel_parent);
if (parent != diskid)
continue;
printf (" %s ", get_vstr (joff+0x18+rel_objid));
printf ("Offset: 0x%08llX ", SWAB64 (joff+0x24+rel_name));
temp = get_vnum (joff+0x34+rel_name);
printf ("Length: 0x%08llX (%lld MB)\n", temp, temp>>11);
}
}
printf ("\n");
return 0;
}
/* O(n^3)? This is getting silly */
int dump_volumes (__u8 *block)
{
__u64 temp;
int vblocks;
int vbsize;
int i;
int j;
int k;
int iobj;
int jobj;
__u8 *ioff;
__u8 *joff;
__u8 *koff;
if (!block)
return 1;
if (MAGIC_VMDB != *((__u32*) block))
{
printf ("not a VMDB\n");
return 1;
}
printf ("VOLUME DEFINITIONS:\n");
printf ("\n");
vblocks = SWAB32 (block+4);
vbsize = SWAB32 (block+8);
for (i = 4; i < vblocks; i++)
{
int rel_objid;
int rel_name;
int rel_vtype;
ioff = block + i*vbsize;
if (MAGIC_VBLK != *((__u32*) ioff))
break;
if (VBLK_VOLU != ioff[19])
continue;
/* Calculate relative offsets */
rel_objid = 1 + ioff[0x18];
rel_name = 1 + ioff[0x18+rel_objid] + rel_objid;
rel_vtype = 1 + ioff[0x18+rel_name] + rel_name;
if (ioff[0x2F+rel_vtype] == 0x02) /* last byte of flags */
printf ("Mirrored ");
iobj = get_vnum (ioff+0x18); /* objid of volume */
printf ("%s ", get_vstr (ioff+0x18+rel_objid));
temp = get_vnum (ioff+0x40+rel_vtype);
printf ("Size: 0x%08llX (%lld MB)\n", temp, temp >> 11);
for (j = 4; j < vblocks; j++)
{
int rel_objid;
int rel_name;
int rel_vstate;
int parent;
joff = block + j*vbsize;
if (MAGIC_VBLK != *((__u32*) joff))
break;
if (VBLK_COMP != joff[19])
continue;
/* Calculate relative offsets */
rel_objid = 1 + joff[0x18];
rel_name = 1 + joff[0x18+rel_objid] + rel_objid;
rel_vstate = 1 + joff[0x18+rel_name] + rel_name;
parent = get_vnum (joff+0x2F+rel_vstate);
if (parent != iobj)
continue;
jobj = get_vnum (joff+0x18); /* objid of component */
printf (" %s -\n", get_vstr (joff+0x18+rel_objid));
for (k = 4; k < vblocks; k++)
{
int rel_objid;
int rel_name;
int rel_size;
koff = block + k*vbsize;
if (MAGIC_VBLK != *((__u32*) koff))
break;
if (VBLK_PART != koff[19])
continue;
/* Calculate relative offsets */
rel_objid = 1 + koff[0x18];
rel_name = 1 + koff[0x18+rel_objid] + rel_objid;
rel_size = 1 + koff[0x34+rel_name] + rel_name;
parent = get_vnum (koff+0x34+rel_size);
if (parent != jobj)
continue;
printf (" %s ", get_vstr (koff+0x18+rel_objid));
printf ("VolumeOffset: 0x%08llX ", SWAB64 (koff+0x2C+rel_name));
printf ("Offset: 0x%08llX ", SWAB64 (koff+0x24+rel_name));
printf ("Length: 0x%08llX\n", get_vnum (koff+0x34+rel_name));
}
}
}
printf ("\n");
return 0;
}
int get_partition (FILE *file, __u32 *first, __u32 *last)
{
__u8 buffer[512];
int ret = 1;
if (!first || !last)
{
goto gp_end;
}
*first = 0;
*last = 0;
if (fread (buffer, sizeof (buffer), 1, file) != 1)
{
printf ("gp fread\n");
goto gp_end;
}
/* Check this is the partition sector */
if (!(((buffer[510] == 0x55) && (buffer[511] == 0xAA)) ||
((buffer[510] == 0xAA) && (buffer[511] == 0x55))))
{
printf ("not a partition sector\n");
goto gp_end;
}
if (buffer[450] != 0x42) /* M$ dynamic disk */
{
printf ("partition type\n");
goto gp_end;
}
if (buffer[466] != 0x00)
{
printf ("multiple partitions!\n"); /* ignore for now */
}
/* little endian */
*first = *((__u32 *) (buffer + 454));
*last = *((__u32 *) (buffer + 458)); /* actually this is the size */
*last += *first - 1;
ret = 0;
gp_end:
return ret;
}
int main (int argc, char *argv[])
{
const int bufsize = 1048576; /* 1MiB */
__u32 first = 0;
__u32 last = 0;
__u32 db = 0;
__u8 *buffer = NULL;
FILE *file = NULL;
int ret = 1;
if (argc != 2)
{
printf ("args\n");
goto end;
}
file = fopen (argv[1], "r");
if (!file)
{
printf ("fopen\n");
goto end;
}
if (get_partition (file, &first, &last))
{
printf ("get_partition\n");
goto close;
}
/* check PRIVHEAD exists, else no LDM */
printf ("Device: %s\n", argv[1]);
printf ("Physical Size: %lld MiB\n", (__u64) (last+1) >> 11);
printf ("Logical Size: %lld MiB\n", (__u64) (last-first-2047) >> 11);
printf ("\n");
db = last - 2047; /* 1 MiB from the end */
if (db > 0x400000)
{
printf ("Disk exceeds 2GiB limit, giving up\n");
goto close;
}
db <<= 9; /* convert to bytes */
buffer = malloc (bufsize);
if (!buffer)
{
printf ("malloc\n");
goto free;
}
memset (buffer, 0, bufsize);
if (fseek (file, -bufsize, SEEK_END))
{
printf ("fseek\n");
goto free;
}
if (fread (buffer, bufsize, 1, file) != 1)
{
printf ("fread\n");
goto free;
}
dump_privhead (buffer + 0xE8000);
//dump_privhead (buffer + 0xFFE00);
//dump_tocblock (buffer + 0x200);
dump_tocblock (buffer + 0x400);
//dump_tocblock (buffer + 0xFFA00);
//dump_tocblock (buffer + 0xFFC00);
dump_vmdb (buffer + 0x2200);
dump_disks (buffer + 0x2200);
dump_volumes (buffer + 0x2200);
ret = 0;
free:
free (buffer);
close:
fclose (file);
end:
return ret;
}
|