Click here to Skip to main content
15,896,063 members
Articles / Programming Languages / C++

An NTFS Parser Lib

Rate me:
Please Sign up or sign in to vote.
4.96/5 (44 votes)
30 May 2010BSD16 min read 202.3K   12.5K   101  
A C++ library to help in parsing an NTFS volume, file record and attributes.
// list files and directories
// usage: ntfsdir "path"
// eg. ntfsdir c:\windows
// eg. ntfsdir "c:\program files\common files"

#include "../../NTFSLib/NTFS.h"
#include <stdio.h>

void usage()
{
	printf("Invalid parameter\n");
	printf("Usage: ntfsdir \"path\"\n");
	printf("eg. ntfsdir c:\n");
	printf("eg. ntfsdir c:\\windows\n");
	printf("eg. ntfsdir \"c:\\program files\\common files\"\n");
}

// get volume name 'C', 'D', ...
// *ppath -> "c:\program files\common files"
char getvolume(char **ppath)
{
	char *p = *ppath;
	char volname;

	// skip leading blank and "
	while (*p)
	{
		if (*p == ' ' || *p == '"')
			p++;
		else
			break;
	}
	if (*p == '\0')
		return '\0';
	else
	{
		volname = *p;
		p++;
	}

	// skip blank
	while(*p)
	{
		if (*p == ' ')
			p++;
		else
			break;
	}
	if (*p == '\0')
		return '\0';

	if (*p != ':')
		return '\0';

	// forward to '\' or string end
	while (*p)
	{
		if (*p != '\\')
			p++;
		else
			break;
	}
	// forward to not '\' and not ", or string end
	while (*p)
	{
		if (*p == '\\' || *p == '"')
			p++;
		else
			break;
	}

	*ppath = p;
	return volname;
}

// get sub directory name
// *ppath -> "program files\common files"
int getpathname(char **ppath, char *pathname)
{
	int len = 0;
	char *p = *ppath;

	// copy until '\' or " or string ends or buffer full
	while (*p && len < MAX_PATH)
	{
		pathname[len] = *p;
		len++;
		p++;

		if (*p == '\\' || *p == '\"')
			break;
	}
	pathname[len] = '\0';

	// forward to not '\' and not ", or string end
	while (*p)
	{
		if (*p == '\\' || *p == '\"')
			p++;
		else
			break;
	}

	*ppath = p;
	return len;
}

int totalfiles = 0;
int totaldirs = 0;

void printfile(const CIndexEntry *ie)
{
	// Hide system metafiles
	if (ie->GetFileReference() < MFT_IDX_USER)
		return;

	// Ignore DOS alias file names
	if (!ie->IsWin32Name())
		return;

	FILETIME ft;
	char fn[MAX_PATH];
	int fnlen = ie->GetFileName(fn, MAX_PATH);
	if (fnlen > 0)
	{
		ie->GetFileTime(&ft);
		SYSTEMTIME st;
		if (FileTimeToSystemTime(&ft, &st))
		{
			printf("%d-%02d-%02d  %02d:%02d\t%s    ", st.wYear, st.wMonth, st.wDay,
				st.wHour, st.wMinute, ie->IsDirectory()?"<DIR>":"     ");

			if (!ie->IsDirectory())
				printf("%I64u\t", ie->GetFileSize());
			else
				printf("\t");

			printf("<%c%c%c>\t%s\n", ie->IsReadOnly()?'R':' ',
				ie->IsHidden()?'H':' ', ie->IsSystem()?'S':' ', fn);
		}

		if (ie->IsDirectory())
			totaldirs ++;
		else
			totalfiles ++;
	}
}

int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		usage();
		return -1;
	}

	char *path = argv[1];

	char volname;
	volname = getvolume(&path);
	if (!volname)
	{
		usage();
		return -1;
	}

	CNTFSVolume volume(volname);
	if (!volume.IsVolumeOK())
	{
		printf("Cannot get NTFS BPB from boot sector of volume %c\n", volume);
		return -1;
	}

	// get root directory info

	CFileRecord fr(&volume);

	// we only need INDEX_ROOT and INDEX_ALLOCATION
	// don't waste time and ram to parse unwanted attributes
	fr.SetAttrMask(MASK_INDEX_ROOT | MASK_INDEX_ALLOCATION);

	if (!fr.ParseFileRecord(MFT_IDX_ROOT))
	{
		printf("Cannot read root directory of volume %c\n", volname);
		return -1;
	}

	if (!fr.ParseAttrs())
	{
		printf("Cannot parse attributes\n");
		return -1;
	}

	// find subdirectory

	char pathname[MAX_PATH];
	int pathlen;

	while (1)
	{
		pathlen = getpathname(&path, pathname);
		if (pathlen < 0)	// parameter syntax error
		{
			usage();
			return -1;
		}
		if (pathlen == 0)
			break;	// no subdirectories

		CIndexEntry ie;
		if (fr.FindSubEntry(pathname, ie))
		{
			if (ie.IsDirectory())
			{
				if (!fr.ParseFileRecord(ie.GetFileReference()))
				{
					printf("Cannot read directory %s\n", pathname);
					return -1;
				}
				if (!fr.ParseAttrs())
				{
					printf("Cannot parse attributes\n");
					return -1;
				}
			}
			else
			{
				printf("%s is not a directory\n", pathname);
				return -1;
			}
		}
		else
		{
			printf("Cannot find directory %s\n", pathname);
			return -1;
		}
	}

	// list it !

	fr.TraverseSubEntries(printfile);

	printf("Files: %d, Directories: %d\n", totalfiles, totaldirs);

	return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
China China
From Shanghai, China

Comments and Discussions