summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@thewalter.net>2004-04-01 04:35:55 +0000
committerStef Walter <stef@thewalter.net>2004-04-01 04:35:55 +0000
commitde5167a304b5e3b2db7462329334ac01d492d72c (patch)
treef091b1c7679c9120579875d17bbf7295a4ccbc9f
parent048987b4e95b70a4559b9163d90e57dd69097203 (diff)
- Fixes all round
- Uncontiguous FAT - Move to C (instead of C++) - Preparing for porting
-rw-r--r--config.win32.h217
-rw-r--r--src/StdAfx.cpp29
-rw-r--r--src/StdAfx.h44
-rw-r--r--src/compat.c457
-rw-r--r--src/compat.h185
-rw-r--r--src/debug.h56
-rw-r--r--src/drive.cpp137
-rw-r--r--src/drive.h139
-rw-r--r--src/list.c131
-rw-r--r--src/locks.h61
-rw-r--r--src/main.c222
-rw-r--r--src/memref.h48
-rw-r--r--src/misc.c152
-rw-r--r--src/ntfs.c140
-rw-r--r--src/ntfs.h341
-rw-r--r--src/ntfsx.c605
-rw-r--r--src/ntfsx.h209
-rw-r--r--src/scrounge.c1002
-rw-r--r--src/scrounge.h58
-rw-r--r--src/search.c32
-rw-r--r--src/usuals.h62
-rw-r--r--src/win32.c78
-rw-r--r--win32/win32.dsp86
-rw-r--r--win32/win32.dsw2
24 files changed, 2806 insertions, 1687 deletions
diff --git a/config.win32.h b/config.win32.h
new file mode 100644
index 0000000..13a057a
--- /dev/null
+++ b/config.win32.h
@@ -0,0 +1,217 @@
+/* Configure options for WIN32 */
+
+#define MAX_BUFF 0x0F00000
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to 1 if using `alloca.c'. */
+/* #undef C_ALLOCA */
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define to 1 if the system has the type `bool'. */
+/* #undef HAVE_BOOL */
+
+/* Define to 1 if the system has the type `byte'. */
+/* #undef HAVE_BYTE */
+
+/* Define to 1 if you have the `bzero' function. */
+/* #define HAVE_BZERO 1 */
+
+/* Define to 1 if you have the `chdir' function. */
+/* #define HAVE_CHDIR 1 */
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+/* #define HAVE_DIRENT_H 1 */
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #define HAVE_ERR_H 1 */
+
+/* Define to 1 if your system has a working `fnmatch' function. */
+/* #define HAVE_FNMATCH 1 */
+
+/* Define to 1 if you have the `getcwd' function. */
+/* #define HAVE_GETCWD 1 */
+
+/* Define to 1 if you have the `getopt' function. */
+/* #define HAVE_GETOPT 1 */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+/* #define HAVE_INTTYPES_H 1 */
+
+/* Define to 1 if you have the `malloc' function. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Define to 1 if you have the `stat' function. */
+/* #define HAVE_STAT 1 */
+
+/* Define to 1 if `stat' has the bug that it succeeds when given the
+ zero-length file name argument. */
+/* #undef HAVE_STAT_EMPTY_STRING_BUG */
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+/* #define HAVE_STRCASECMP 1 */
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRICMP 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+/* #define HAVE_STRCASESTR 1 */
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strcpy' function. */
+#define HAVE_STRCPY 1
+
+/* Define to 1 if you have the `strcat' function. */
+#define HAVE_STRCAT 1
+
+/* Define to 1 if you have the `strcspn' function. */
+#define HAVE_STRCSPN 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+/* #define HAVE_STRINGS_H 1 */
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #define HAVE_STRLCPY 1 */
+
+/* Define to 1 if you have the `strncpy' function. */
+#define HAVE_STRNCPY 1
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #define HAVE_STRLCAT 1 */
+
+/* Define to 1 if you have the `strncat' function. */
+#define HAVE_STRNCAT 1
+
+/* Define to 1 if you have the `strncasecmp' function. */
+/* #define HAVE_STRNCASECMP 1 */
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#define HAVE_STRNICMP 1
+
+/* Define to 1 if you have the `strndup' function. */
+/* #undef HAVE_STRNDUP */
+
+/* Define to 1 if you have the `strrchr' function. */
+#define HAVE_STRRCHR 1
+
+/* Define to 1 if you have the `strspn' function. */
+#define HAVE_STRSPN 1
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if the system has the type `uint'. */
+/* #define HAVE_UINT 1 */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #define HAVE_UNISTD_H 1 */
+
+/* Define to 1 if you have the `vasprintf' function. */
+/* #define HAVE_VASPRINTF 1 */
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `vsnprintf' function. */
+/* #define HAVE_VSNPRINTF 1 */
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
+
+/* Name of package */
+#define PACKAGE "rep"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "nielsen@memberwebs.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "rep"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "rep 2.1.2b"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "rep"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.1.2b"
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+/* #undef STACK_DIRECTION */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "2.1.1b"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/src/StdAfx.cpp b/src/StdAfx.cpp
deleted file mode 100644
index d939e46..0000000
--- a/src/StdAfx.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
-
-// stdafx.cpp : source file that includes just the standard includes
-// Scrounge.pch will be the pre-compiled header
-// stdafx.obj will contain the pre-compiled type information
-
-#include "stdafx.h"
-
diff --git a/src/StdAfx.h b/src/StdAfx.h
deleted file mode 100644
index 38f0a95..0000000
--- a/src/StdAfx.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
-// stdafx.h : include file for standard system include files,
-// or project specific include files that are used frequently, but
-// are changed infrequently
-//
-
-#if !defined(AFX_STDAFX_H__552C4258_1192_4B38_948A_887884424C46__INCLUDED_)
-#define AFX_STDAFX_H__552C4258_1192_4B38_948A_887884424C46__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#include <stdio.h>
-#include <windows.h>
-#include <tchar.h>
-#include "memref.h"
-
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_STDAFX_H__552C4258_1192_4B38_948A_887884424C46__INCLUDED_)
diff --git a/src/compat.c b/src/compat.c
new file mode 100644
index 0000000..5ee1c0e
--- /dev/null
+++ b/src/compat.c
@@ -0,0 +1,457 @@
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "compat.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifndef HAVE_TOLOWER
+int tolower(int c)
+{
+ if('A' <= c && c <= 'Z')
+ c += 'a' - 'A';
+ return c;
+}
+#define HAVE_TOLOWER
+#endif
+
+
+#ifndef HAVE_STRDUP
+
+#ifndef HAVE_MALLOC
+#error Need a working malloc.
+#endif
+
+char* strdup(const char* str)
+{
+ char* dup = (char*)malloc((strlen(str) + 1) * sizeof(char));
+ if(dup)
+ strcpy(dup, str);
+ return dup;
+}
+#define HAVE_STRDUP
+#endif
+
+
+#ifndef HAVE_STRNDUP
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+char* strndup(const char* str, size_t cnt)
+{
+ char* buff = malloc(sizeof(char) * (cnt + 1));
+ if(buff)
+ {
+ memcpy(buff, str, sizeof(char) * cnt);
+ buff[cnt] = 0;
+ }
+ return buff;
+}
+#endif
+
+
+#ifndef HAVE_STRCASESTR
+char* strcasestr(const char* buff, const char* str)
+{
+ const char* ptr = buff;
+
+ while (*ptr != 0x00)
+ {
+ const char* one = ptr;
+ const char* two = str;
+
+ while (tolower(*one) == tolower(*two))
+ {
+ one++;
+ two++;
+ if (*two == 0x00)
+ return (char*) ptr;
+ }
+ ptr++;
+ }
+ return NULL;
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+
+#ifndef HAVE_STRNCPY
+#error neither strncpy or strlcpy found
+#endif
+
+void strlcpy(char* dest, const char* src, size_t count)
+{
+ strncpy(dest, src, count);
+ dest[count - 1] = 0;
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+
+#ifndef HAVE_STRNCAT
+#error neither strncat or strlcat found
+#endif
+
+void strlcat(char* dest, const char* src, size_t count)
+{
+ strncat(dest, src, count);
+ dest[count - 1] = 0;
+}
+#endif
+
+
+#ifndef HAVE_VASPRINTF
+
+#ifndef HAVE_VSNPRINTF
+#error neither vasprintf or vsnprintf found
+#endif
+
+int vasprintf(char** ret, const char* format, va_list vl)
+{
+ size_t size = 32;
+ int c;
+ *ret = NULL;
+
+ do
+ {
+ /* Double the buffer size for next time around */
+ size += size;
+
+ if(*ret)
+ free(*ret);
+
+ *ret = (char*)malloc(sizeof(char) * size);
+
+ if(!(*ret))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ c = vsnprintf(*ret, size, format, vl);
+ }
+ while(c < 0);
+
+ return c;
+}
+
+#endif
+
+
+/*
+ * We need to get a better check for this one.
+ * Basically have to make a variable __progname if none
+ * exist
+ */
+
+#ifndef HAVE_UNISTD_H
+
+char* __progname = 0;
+char prognamebuf[256];
+
+void fixprogname()
+{
+ if(__progname == 0)
+ {
+ const char* beg = strrchr(_pgmptr, '\\');
+ const char* temp = strrchr(_pgmptr, '/');
+ beg = (beg > temp) ? beg : temp;
+ beg = (beg) ? beg + 1 : _pgmptr;
+
+ temp = strrchr(_pgmptr, '.');
+ temp = (temp > beg) ? temp : _pgmptr + strlen(_pgmptr);
+
+ if((temp - beg) > 255)
+ temp = beg + 255;
+
+ strncpy(prognamebuf, beg, temp - beg);
+ prognamebuf[temp - beg] = 0;
+ __progname = prognamebuf;
+ }
+}
+#endif
+
+
+
+#ifndef HAVE_GETOPT
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char* optarg;
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int getopt(int nargc, char* const* nargv, const char* ostr)
+{
+ static char* place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ fixprogname();
+
+ if(optreset || !*place) /* update scanning pointer */
+ {
+ optreset = 0;
+ if(optind >= nargc || *(place = nargv[optind]) != '-')
+ {
+ place = EMSG;
+ return (-1);
+ }
+
+ if (place[1] && *++place == '-') /* found "--" */
+ {
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ } /* option letter okay? */
+
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt)))
+ {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1.
+ */
+ if(optopt == (int)'-')
+ return (-1);
+ if(!*place)
+ ++optind;
+ if(opterr && *ostr != ':' && optopt != BADCH)
+ (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname, optopt);
+ return(BADCH);
+ }
+ if (*++oli != ':') /* don't need argument */
+ {
+ optarg = NULL;
+ if(!*place)
+ ++optind;
+ }
+ else /* need an argument */
+ {
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) /* no arg */
+ {
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if(opterr)
+ (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname, optopt);
+ return(BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+}
+#endif
+
+
+#ifndef HAVE_ERR_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+static FILE *err_file; /* file to use for error output */
+static void (*err_exit)(int);
+
+/*
+ * This is declared to take a `void *' so that the caller is not required
+ * to include <stdio.h> first. However, it is really a `FILE *', and the
+ * manual page documents it as such.
+ */
+void err_set_file(void *fp)
+{
+ if (fp)
+ err_file = fp;
+ else
+ err_file = stderr;
+}
+
+void err_set_exit(void (*ef)(int))
+{
+ err_exit = ef;
+}
+
+void err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrc(eval, errno, fmt, ap);
+ va_end(ap);
+}
+
+void verr(int eval, const char *fmt, va_list ap)
+{
+ verrc(eval, errno, fmt, ap);
+}
+
+void errc(int eval, int code, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrc(eval, code, fmt, ap);
+ va_end(ap);
+}
+
+void verrc(int eval, int code, const char *fmt, va_list ap)
+{
+ fixprogname();
+ if (err_file == 0)
+ err_set_file((FILE *)0);
+ fprintf(err_file, "%s: ", __progname);
+ if (fmt != NULL) {
+ vfprintf(err_file, fmt, ap);
+ fprintf(err_file, ": ");
+ }
+ fprintf(err_file, "%s\n", strerror(code));
+ if (err_exit)
+ err_exit(eval);
+ exit(eval);
+}
+
+void errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verrx(eval, fmt, ap);
+ va_end(ap);
+}
+
+void verrx(int eval, const char *fmt, va_list ap)
+{
+ fixprogname();
+ if (err_file == 0)
+ err_set_file((FILE *)0);
+ fprintf(err_file, "%s: ", __progname);
+ if (fmt != NULL)
+ vfprintf(err_file, fmt, ap);
+ fprintf(err_file, "\n");
+ if (err_exit)
+ err_exit(eval);
+ exit(eval);
+}
+
+void warn(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnc(errno, fmt, ap);
+ va_end(ap);
+}
+
+void vwarn(const char *fmt, va_list ap)
+{
+ vwarnc(errno, fmt, ap);
+}
+
+void warnc(int code, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnc(code, fmt, ap);
+ va_end(ap);
+}
+
+void vwarnc(int code, const char *fmt, va_list ap)
+{
+ fixprogname();
+ if (err_file == 0)
+ err_set_file((FILE *)0);
+ fprintf(err_file, "%s: ", __progname);
+ if (fmt != NULL)
+ {
+ vfprintf(err_file, fmt, ap);
+ fprintf(err_file, ": ");
+ }
+ fprintf(err_file, "%s\n", strerror(code));
+}
+
+void warnx(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+}
+
+void vwarnx(const char *fmt, va_list ap)
+{
+ fixprogname();
+ if(err_file == 0)
+ err_set_file((FILE*)0);
+ fprintf(err_file, "%s: ", __progname);
+ if(fmt != NULL)
+ vfprintf(err_file, fmt, ap);
+ fprintf(err_file, "\n");
+}
+
+#endif
+
+
+
+#ifndef HAVE_STRLWR
+
+char* strlwr(char *string)
+{
+ char * cp;
+ for (cp=string; *cp; ++cp)
+ {
+ if('A' <= *cp && *cp <= 'Z')
+ *cp += 'a' - 'A';
+ }
+ return(string);
+}
+
+#endif
+
+
+
+#ifndef HAVE_REALLOCF
+
+void* reallocf(void* ptr, size_t size)
+{
+ void* ret = realloc(ptr, size);
+
+ if(!ret && size)
+ free(ptr);
+
+ return ret;
+}
+
+#endif
diff --git a/src/compat.h b/src/compat.h
new file mode 100644
index 0000000..cc3b73e
--- /dev/null
+++ b/src/compat.h
@@ -0,0 +1,185 @@
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#ifndef _COMPAT_H_
+#define _COMPAT_H_
+
+/* Force use of win32 configuration if compiling there */
+#ifdef _WIN32
+#include "../config.win32.h"
+#else
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+#endif
+
+#ifndef MAX_PATH
+ #ifdef _MAX_PATH
+ #define MAX_PATH _MAX_PATH
+ #else
+ #define MAX_PATH 256
+ #endif
+#endif
+
+#ifndef HAVE_STDARG_H
+#error ERROR: Must have a working <stdarg.h> header
+#else
+#include <stdarg.h>
+#endif
+
+
+#ifndef HAVE_STAT
+#ifdef _WIN32
+#define S_IFDIR _S_IFDIR
+#define HAVE_STAT
+#else
+#error ERROR: Must have a working 'stat' function
+#endif
+#endif
+
+#ifndef HAVE_GETCWD
+#ifdef _WIN32
+#include <direct.h>
+#define getcwd _getcwd
+#define HAVE_GETCWD
+#else
+#error ERROR: Must have a working 'getcwd' function
+#endif
+#endif
+
+#ifndef HAVE_CHDIR
+#ifdef _WIN32
+#include <direct.h>
+#define chdir _chdir
+#define HAVE_CHDIR
+#else
+#error ERROR: Must have a working 'chdir' function
+#endif
+#endif
+
+#ifndef HAVE_TOLOWER
+int tolower(int c);
+#endif
+
+#ifndef HAVE_STRDUP
+char* strdup(const char* str);
+#endif
+
+#ifndef HAVE_STRNDUP
+char* strndup(const char* str, size_t cnt);
+#endif
+
+#ifndef HAVE_STRCASESTR
+char* strcasestr(const char* big, const char* little);
+#endif
+
+#ifndef HAVE_STRCASECMP
+#ifdef HAVE_STRICMP
+#define strcasecmp stricmp
+#else
+#error ERROR: Must have either 'strcasecmp' or 'stricmp'
+#endif
+#endif
+
+#ifndef HAVE_STRCASECMP
+#ifdef HAVE_STRICMP
+#define strncasecmp strnicmp
+#else
+#error ERROR: Must have either 'strncasecmp' or 'strnicmp'
+#endif
+#endif
+
+
+#ifndef NULL
+#define NULL (void*)0
+#endif
+
+#ifndef __cplusplus
+typedef unsigned char bool;
+#define false 0x00
+#define true 0x01
+#endif
+
+#ifndef HAVE_BYTE
+typedef unsigned char byte;
+#define HAVE_BYTE
+#endif
+
+#ifndef HAVE_UINT
+typedef unsigned int uint;
+#define HAVE_UINT
+#endif
+
+#ifndef HAVE_STRLCPY
+void strlcpy(char* dest, const char* src, size_t count);
+#endif
+
+#ifndef HAVE_STRLCAT
+void strlcat(char* dest, const char* src, size_t count);
+#endif
+
+#ifndef HAVE_VSNPRINTF
+
+#ifdef _WIN32
+#define vsnprintf _vsnprintf
+#define HAVE_VSNPRINTF
+#else
+#ifndef HAVE_VASPRINTF
+#error ERROR: Must have a working 'vsnprintf' or 'vasprintf' function
+#endif
+#endif
+#endif
+
+#ifndef HAVE_VASPRINTF
+int vasprintf(char** ret, const char* format, va_list vl);
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef HAVE_GETOPT
+extern char* optarg;
+extern int optind, opterr, optopt;
+int getopt(int nargc, char* const* nargv, const char* ostr);
+#endif
+
+#ifndef HAVE_ERR_H
+#include <stdarg.h>
+void err_set_file(void *fp);
+void err_set_exit(void (*ef)(int));
+void err(int eval, const char *fmt, ...);
+void verr(int eval, const char *fmt, va_list ap);
+void errc(int eval, int code, const char *fmt, ...);
+void verrc(int eval, int code, const char *fmt, va_list ap);
+void errx(int eval, const char *fmt, ...);
+void verrx(int eval, const char *fmt, va_list ap);
+void warn(const char *fmt, ...);
+void vwarn(const char *fmt, va_list ap);
+void warnc(int code, const char *fmt, ...);
+void vwarnc(int code, const char *fmt, va_list ap);
+void warnx(const char *fmt, ...);
+void vwarnx(const char *fmt, va_list ap);
+#endif
+
+#ifndef HAVE_REALLOCF
+void* reallocf(void* ptr, size_t size);
+#endif
+
+#endif
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..e776fd1
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,56 @@
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#ifdef _DEBUG
+
+#include <stdarg.h>
+
+#ifndef ASSERT
+ #ifdef ATLASSERT
+ #define ASSERT ATLASSERT
+ #else
+ #include <assert.h>
+ #define ASSERT assert
+ #endif
+#endif
+
+#ifndef VERIFY
+#define VERIFY(f) ASSERT(f)
+#endif
+
+#ifndef DEBUG_ONLY
+#define DEBUG_ONLY(f) (f)
+#endif
+
+
+#else /* !DEBUG */
+
+#ifndef ASSERT
+#define ASSERT(f) ((void)0)
+#endif
+
+#ifndef VERIFY
+#define VERIFY(f) ((void)(f))
+#endif
+
+#ifndef DEBUG_ONLY
+#define DEBUG_ONLY(f) ((void)0)
+#endif
+
+#endif /* _DEBUG */
diff --git a/src/drive.cpp b/src/drive.cpp
deleted file mode 100644
index f485cf6..0000000
--- a/src/drive.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
-
-#include "drive.h"
-#include "memref.h"
-#include <malloc.h>
-#include <string.h>
-#include <stdio.h>
-
-
-PartitionInfo* CreatePartitionInfo()
-{
- PartitionInfo* pInfo = (PartitionInfo*)refalloc(sizeof(PartitionInfo));
- if(pInfo)
- memset(pInfo, 0, sizeof(PartitionInfo));
-
- return pInfo;
-}
-
-void FreePartitionInfo(PartitionInfo* pInfo)
-{
- if(pInfo)
- {
- if(pInfo->pLocks)
- free(pInfo->pLocks);
-
- refrelease(pInfo);
- }
-}
-
-// These locks are used to signify which
-struct DriveLock
-{
- uint64 beg;
- uint64 end;
-};
-
-
-bool IntersectRange(uint64& b1, uint64& e1, uint64 b2, uint64 e2)
-{
- // TODO: (later) This is stupid! There's a simple quick way
- // need to update
-
- if(b1 <= b2 && e1 > b2 && b1 < e2) // Overlaps the first portion
- e1 = e2;
- else if(b1 < e2 && e1 >= e2 && b2 < e1) // Overlaps second portion
- b1 = b2;
- else if(b1 > b2 && e1 < e2) // Encompassed
- { }
- else if (b1 == b2 && e1 == e2) // Identical
- { }
- else
- return false;
-
- return true;
-}
-
-void AddLocationLock(PartitionInfo* pInfo, uint64 beg, uint64 end)
-{
- if(pInfo->cLocks <= pInfo->curLock)
- {
- pInfo->cLocks += 0x400;
- pInfo->pLocks = (DriveLock*)realloc(pInfo->pLocks, sizeof(DriveLock) * pInfo->cLocks);
- }
-
- // TODO: Implement a more efficient method here!
-
- if(pInfo->pLocks)
- {
- bool bFound = false;
-
- // Go through and check for a current lock we can tag onto
- for(uint32 i = 0; i < pInfo->curLock; i++)
- {
- if(IntersectRange(pInfo->pLocks[i].beg, pInfo->pLocks[i].end,
- beg, end))
- {
- bFound = true;
- }
- }
-
- if(!bFound)
- {
- pInfo->pLocks[pInfo->curLock].beg = beg;
- pInfo->pLocks[pInfo->curLock].end = end;
- pInfo->curLock++;
- }
- }
-}
-
-bool CheckLocationLock(PartitionInfo* pInfo, uint64& sec)
-{
- // Go through and check for a lock
- for(uint32 i = 0; i < pInfo->curLock; i++)
- {
- if(sec >= pInfo->pLocks[i].beg &&
- sec < pInfo->pLocks[i].end)
- {
- sec = pInfo->pLocks[i].end;
- return true;
- }
- }
-
- return false;
-}
-
-#ifdef _DEBUG
-void DumpLocationLocks(PartitionInfo* pInfo)
-{
- for(uint32 i = 0; i < pInfo->curLock; i++)
- {
- printf("%u\t%u\n", (uint32)pInfo->pLocks[i].beg, (uint32)pInfo->pLocks[i].end);
- }
-
- printf("\n");
-}
-#endif
diff --git a/src/drive.h b/src/drive.h
index f0df9f1..4c52584 100644
--- a/src/drive.h
+++ b/src/drive.h
@@ -1,94 +1,89 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
#ifndef __DRIVE_H__20010822
#define __DRIVE_H__20010822
#include "usuals.h"
-const uint16 kSectorSize = 0x200;
-const uint64 kInvalidSector = 0xFFFFFFFFFFFFFFFF;
-struct DriveLock;
-
-struct PartitionInfo
-{
- uint32 firstSector;
- uint32 lastSector;
- uint32 offMFT; // In sectors
- byte clusterSize; // In sectors
-
- DriveLock* pLocks;
- uint32 cLocks;
- uint32 curLock;
-};
+#define kSectorSize 0x200
+#define kInvalidSector 0xFFFFFFFFFFFFFFFF
-PartitionInfo* CreatePartitionInfo();
-void FreePartitionInfo(PartitionInfo* pInfo);
+typedef struct _ntfsx_mftmap ntfsx_mftmap;
+typedef struct _drivelocks drivelocks;
+typedef struct _partitioninfo
+{
+ uint32 first; /* The first sector (in sectors) */
+ uint32 end; /* The end sector (in sectors) */
+ uint32 mft; /* Offset into the MFT (in sectors) */
+ byte cluster; /* Cluster size (in sectors) */
+ int device; /* A handle to an open device */
+
+ /* Some other context stuff about the drive */
+ drivelocks* locks;
+ ntfsx_mftmap* mftmap;
+}
+partitioninfo;
#pragma pack(push, drive)
#pragma pack(1)
-const byte kPartition_Invalid = 0;
-const byte kPartition_Extended = 5;
-const byte kPartition_ExtendedLBA = 15;
+#define kPartition_Invalid 0
+#define kPartition_Extended 5
+#define kPartition_ExtendedLBA 15
-// Partition table entry
-struct Drive_PartEntry
+/* Partition table entry */
+typedef struct _drive_partentry
{
- byte active; // partition bootable flag
- byte starthead; // starting head
- byte startsector; // starting sector and 2 MS bits of cylinder
- byte startcylinder; // starting cylinder (low 8 bits)
- byte system; // partition type
- byte endhead; // ending head
- byte endsector; // ending sector and 2 MS bits of cylinder
- byte endcylinder; // ending cylinder (low 8 bits)
- uint32 startsec; // absolute starting sector
- uint32 endsec; // absolute ending sector
-};
-
-const uint16 kMBR_Sig = 0xAA55;
-
-// Master Boot Record
-struct Drive_MBR
+ byte active; /* partition bootable flag */
+ byte starthead; /* starting head */
+ byte startsector; /* starting sector and 2 MS bits of cylinder */
+ byte startcylinder; /* starting cylinder (low 8 bits) */
+ byte system; /* partition type */
+ byte endhead; /* ending head */
+ byte endsector; /* ending sector and 2 MS bits of cylinder */
+ byte endcylinder; /* ending cylinder (low 8 bits) */
+ uint32 startsec; /* absolute starting sector */
+ uint32 endsec; /* absolute ending sector */
+}
+drive_partentry;
+
+#define kMBR_Sig 0xAA55
+
+/* Master Boot Record */
+typedef struct _drive_mbr
{
- byte fill[0x1be]; // boot code
- Drive_PartEntry partitions[4]; // partition table
- uint16 sig; // 55AAh boot signature
-};
+ byte fill[0x1be]; /* boot code */
+ drive_partentry partitions[4]; /* partition table */
+ uint16 sig; /* 55AAh boot signature */
+}
+drive_mbr;
#pragma pack(pop, drive)
-#define CLUSTER_TO_SECTOR(info, clus) (((clus) * (info).clusterSize) + (info).firstSector)
+#define CLUSTER_TO_SECTOR(info, clus) (((clus) * (info).cluster) + (info).first)
#define SECTOR_TO_BYTES(sec) ((sec) * kSectorSize)
-#define CLUSTER_SIZE(info) ((info).clusterSize * kSectorSize)
-
-bool IntersectRange(uint64& b1, uint64& e1, uint64 b2, uint64 e2);
-void AddLocationLock(PartitionInfo* pInfo, uint64 beg, uint64 end);
-bool CheckLocationLock(PartitionInfo* pInfo, uint64& sec);
-
+#define CLUSTER_SIZE(info) ((info).cluster * kSectorSize)
+/* driveName should be MAX_PATH chars long */
+void makeDriveName(char* driveName, int i);
-#endif //__DRIVE_H__20010822 \ No newline at end of file
+#endif /* __DRIVE_H__ */
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 0000000..28f2952
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,131 @@
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#include <io.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "usuals.h"
+#include "drive.h"
+#include "ntfs.h"
+
+const char kPrintData[] = "\
+ Start Sector End Sector Cluster Size MFT Offset \n\
+==================================================================\n\
+";
+
+const char kPrintDrive[] = "\nDrive: %u\n";
+const char kPrintDriveInfo[] = " %-15u %-15u ";
+const char kPrintNTFSInfo[] = "%-15u %-15u";
+
+int printNTFSInfo(int dd, uint64 tblSector)
+{
+ byte sector[kSectorSize];
+ int64 pos;
+ size_t sz;
+ ntfs_bootsector* boot;
+
+ pos = SECTOR_TO_BYTES(tblSector);
+
+ /* PORT: Windows specific */
+ if(_lseeki64(dd, pos, SEEK_SET) == -1)
+ err(1, "couldn't seek drive");
+
+ sz = read(dd, &sector, kSectorSize);
+ if(sz == -1)
+ err(1, "couldn't read drive");
+
+ if(sz != kSectorSize)
+ errx(1, "unexpected end of drive");
+
+ boot = (ntfs_bootsector*)sector;
+ if(!memcmp(boot->sysId, kNTFS_SysId, sizeof(boot->sysId)))
+ printf(kPrintNTFSInfo, boot->secPerClus, boot->offMFT * boot->secPerClus);
+
+ printf("\n");
+ return 0;
+}
+
+int printPartitionInfo(int dd, uint64 tblSector)
+{
+ drive_mbr mbr;
+ int64 pos;
+ size_t sz;
+ int i;
+
+ ASSERT(sizeof(drive_mbr) == kSectorSize);
+
+ pos = SECTOR_TO_BYTES(tblSector);
+
+ /* PORT: Windows specific */
+ if(_lseeki64(dd, pos, SEEK_SET) == -1)
+ err(1, "couldn't seek drive");
+
+ sz = read(dd, &mbr, sizeof(drive_mbr));
+ if(sz == -1)
+ err(1, "couldn't read drive");
+
+ if(sz != sizeof(drive_mbr))
+ errx(1, "unexpected end of drive");
+
+ if(mbr.sig == kMBR_Sig)
+ {
+ for(i = 0; i < 4; i++)
+ {
+ if(mbr.partitions[i].system == kPartition_Extended ||
+ mbr.partitions[i].system == kPartition_ExtendedLBA)
+ {
+ printPartitionInfo(dd, tblSector + mbr.partitions[i].startsec);
+ }
+ else if(!mbr.partitions[i].system == kPartition_Invalid)
+ {
+ printf(kPrintDriveInfo, (uint32)tblSector + mbr.partitions[i].startsec, (uint32)tblSector + mbr.partitions[i].endsec);
+ printNTFSInfo(dd, tblSector + (uint64)mbr.partitions[i].startsec);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+void scroungeList()
+{
+ char driveName[MAX_PATH];
+ int dd = -1;
+ int i;
+
+ printf(kPrintData);
+
+ /* LIMIT: 256 Drives */
+ for(i = 0; i < 0x100; i++)
+ {
+ makeDriveName(driveName, i);
+
+ dd = open(driveName, _O_BINARY | _O_RDONLY);
+ if(dd != -1)
+ {
+ printf(kPrintDrive, i);
+ printPartitionInfo(dd, 0);
+ close(dd);
+ }
+ }
+}
diff --git a/src/locks.h b/src/locks.h
index d60878c..afc0508 100644
--- a/src/locks.h
+++ b/src/locks.h
@@ -1,32 +1,41 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
-#ifndef __LOCKS_H__20010828
-#define __LOCKS_H__20010828
+#ifndef __LOCKS_H__
+#define __LOCKS_H__
+#include "usuals.h"
-#include "drive.h"
+struct drivelock;
+typedef struct _drivelocks
+{
+ struct drivelock* _locks;
+ uint32 _count;
+ uint32 _current;
+}
+drivelocks;
+void addLocationLock(drivelocks* locks, uint64 beg, uint64 end);
+bool checkLocationLock(drivelocks* locks, uint64 sec);
+#ifdef _DEBUG
+void dumpLocationLocks(drivelocks* locks);
+#endif
-
-#endif //__LOCKS_H__20010828 \ No newline at end of file
+#endif /* __LOCKS_H__ */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..39ff0c9
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,222 @@
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#include <io.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "scrounge.h"
+#include "compat.h"
+
+const char kPrintHelp[] = "\
+usage: scrounge -l \n\
+ List all drive partition information. \n\
+ \n\
+usage: scrounge [-d drive] -s \n\
+ Search drive for NTFS partitions. \n\
+ \n\
+usage: scrounge [-d drive] [-m mftoffset] [-c clustersize] [-o outdir] start end \n\
+ Scrounge data from a partition \n\
+ -d Drive number \n\
+ -m Offset to mft (in sectors) \n\
+ -c Cluster size (in sectors, default of 8) \n\
+ -o Directory to put scrounged files in \n\
+ start First sector of partition \n\
+ end Last sector of partition \n\
+ \n\
+";
+
+#define MODE_SCROUNGE 1
+#define MODE_LIST 2
+#define MODE_SEARCH 3
+
+/* Forward decls */
+int usage();
+
+int main(int argc, char* argv[])
+{
+ int ch = 0;
+ int temp = 0;
+ int mode = 0;
+ int raw = 0;
+ int drive = 0;
+ partitioninfo pi;
+ char driveName[MAX_PATH];
+
+ memset(&pi, 0, sizeof(pi));
+
+ /* TODO: We need to be able to autodetect the cluster size */
+ pi.cluster = 8;
+
+ while((ch = getopt(argc, argv, "c:d:hlm:o:s")) != -1)
+ {
+ switch(ch)
+ {
+
+ /* cluster size */
+ case 'c':
+ {
+ temp = atoi(optarg);
+
+ /* TODO: Check this range */
+ if(temp <= 0 || temp > 128)
+ errx(2, "invalid cluster size (must be between 1 and 128)");
+
+ pi.cluster = temp;
+ mode = MODE_SCROUNGE;
+ }
+ break;
+
+ /* drive number */
+ case 'd':
+ {
+ temp = atoi(optarg);
+
+ /* TODO: Check this range */
+ if(temp < 0 || temp > 128)
+ errx(2, "invalid drive number (must be between 0 and 128)");
+
+ drive = temp;
+ }
+ break;
+
+ /* help mode */
+ case 'h':
+ usage();
+ break;
+
+ /* list mode */
+ case 'l':
+ {
+ if(mode == MODE_SCROUNGE)
+ errx(2, "invalid -l argument in scrounge mode");
+
+ mode = MODE_LIST;
+ }
+ break;
+
+ /* mft offset */
+ case 'm':
+ {
+ temp = atoi(optarg);
+
+ /* TODO: Check this range */
+ if(temp < 0)
+ errx(2, "invalid mft offset (must be positive)");
+
+ pi.mft = temp;
+ mode = MODE_SCROUNGE;
+ }
+ break;
+
+ /* output directory */
+ case 'o':
+ if(chdir(optarg) == -1)
+ err(2, "couldn't change to output directory");
+ break;
+
+ /* search mode */
+ case 's':
+ {
+ if(mode == MODE_SCROUNGE)
+ errx(2, "invalid -s argument in scrounge mode");
+
+ mode = MODE_SEARCH;
+ }
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+
+ if(mode != MODE_SCROUNGE && mode != 0)
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(mode == MODE_SCROUNGE || mode == 0)
+ {
+ /* Get the sectors */
+
+ if(argc < 2)
+ errx(2, "must specify start and end sector of partition");
+
+ if(argc > 2)
+ warnx("ignoring extra arguments");
+
+ temp = atoi(argv[0]);
+ if(temp < 0)
+ errx(2, "invalid start sector (must be positive)");
+
+ pi.first = temp;
+
+ temp = atoi(argv[1]);
+ if(temp < 0 || ((unsigned int)temp) <= pi.first)
+ errx(2, "invalid end sector (must be positive and greater than first)");
+
+ pi.end = temp;
+
+ makeDriveName(driveName, drive);
+
+ pi.device = open(driveName, _O_BINARY | _O_RDONLY);
+ if(pi.device == -1)
+ err(1, "couldn't open drive");
+
+ /* Use mft type search */
+ if(pi.mft != 0)
+ {
+ scroungeUsingMFT(&pi);
+ }
+
+ /* Otherwise it's a raw search */
+ else
+ {
+ warn("Scrounging via raw search. Directory info will be discarded.");
+ scroungeUsingRaw(&pi);
+ }
+ }
+
+ else
+ {
+ if(argc > 0)
+ warnx("ignoring extra arguments");
+
+ /* List partition and drive info */
+ if(mode == MODE_LIST)
+ scroungeList();
+
+ /* Search for NTFS partitions */
+ if(mode == MODE_SEARCH)
+ scroungeSearch(&pi);
+ }
+
+ return 0;
+}
+
+int usage()
+{
+ fprintf(stderr, "%s", kPrintHelp);
+ exit(2);
+}
diff --git a/src/memref.h b/src/memref.h
index a26ac34..1138b63 100644
--- a/src/memref.h
+++ b/src/memref.h
@@ -1,28 +1,24 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
-
-#ifndef __MEMREF_H__20010827
-#define __MEMREF_H__20010827
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#ifndef __MEMREF_H__
+#define __MEMREF_H__
#ifdef _DEBUG
@@ -46,4 +42,4 @@ void _refrelease(void* pBuff);
#endif
-#endif //__MEMREF_H__20010827 \ No newline at end of file
+#endif /* __MEMREF_H__ */
diff --git a/src/misc.c b/src/misc.c
index 8939b73..4f48b1e 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1,38 +1,119 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "usuals.h"
+#include "compat.h"
+#include "memref.h"
+#include "locks.h"
-#include "memref.h"
-#include "malloc.h"
-#include "assert.h"
+/* These locks are used to signify which */
+struct drivelock
+{
+ uint64 beg;
+ uint64 end;
+};
+
+void addLocationLock(drivelocks* locks, uint64 beg, uint64 end)
+{
+ uint32 i;
+
+ if(locks->_count <= locks->_current)
+ {
+ locks->_count += 0x400;
+ locks->_locks = (struct drivelock*)realloc(locks->_locks, sizeof(struct drivelock) * locks->_count);
+ }
-// WARNING!! Not thread safe or very efficient for large
-// amounts of memory allocations
+ /* TODO: Implement a more efficient method here! */
+ /* TODO: What happens when the above memory allocation fails? */
+ if(locks->_locks)
+ {
+ /* Go through and check for a current lock we can tag onto */
+ for(i = 0; i < locks->_current; i++)
+ {
+ if(INTERSECTS(locks->_locks[i].beg, locks->_locks[i].end, beg, end))
+ {
+ locks->_locks[i].beg = min(locks->_locks[i].beg, beg);
+ locks->_locks[i].end = max(locks->_locks[i].end, end);
+ return;
+ }
+ }
+
+ locks->_locks[locks->_current].beg = beg;
+ locks->_locks[locks->_current].end = end;
+ locks->_current++;
+ }
+}
+
+bool checkLocationLock(drivelocks* locks, uint64 sec)
+{
+ uint32 i;
+
+ if(locks->_locks)
+ {
+ /* Go through and check for a lock */
+ for(i = 0; i < locks->_current; i++)
+ {
+ if(sec >= locks->_locks[i].beg &&
+ sec < locks->_locks[i].end)
+ {
+ sec = locks->_locks[i].end;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+#ifdef _DEBUG
+void dumpLocationLocks(drivelocks* locks)
+{
+ uint32 i;
+
+ for(i = 0; i < locks->_current; i++)
+ printf("%u\t%u\n", (uint32)locks->_locks[i].beg, (uint32)locks->_locks[i].end);
+
+ printf("\n");
+}
+#endif
+
+
+
+
+/*
+ * WARNING!! Not thread safe or very efficient for large
+ * amounts of memory allocations
+ */
+
+#ifdef _DEBUG
const size_t kRefSig = 0x1F2F3F4F;
void* _refalloc_dbg(size_t sz)
{
- // Allocate extra counter value before memory
+ /* Allocate extra counter value before memory */
size_t* pMem = (size_t*)malloc(sz * sizeof(size_t) * 2);
if(pMem)
@@ -44,10 +125,11 @@ void* _refalloc_dbg(size_t sz)
return pMem;
}
+#endif
void* _refalloc(size_t sz)
{
- // Allocate extra counter value before memory
+ /* Allocate extra counter value before memory */
size_t* pMem = (size_t*)malloc(sz * sizeof(size_t) * 1);
if(pMem)
@@ -59,11 +141,12 @@ void* _refalloc(size_t sz)
return pMem;
}
+#ifdef _DEBUG
void* _refadd_dbg(void* pBuff)
{
if(pBuff)
{
- // Increment the counter value
+ /* Increment the counter value */
size_t* pMem = (size_t*)pBuff - 2;
assert(pMem[0] == kRefSig);
pMem[1]++;
@@ -71,21 +154,23 @@ void* _refadd_dbg(void* pBuff)
return pBuff;
}
+#endif
void* _refadd(void* pBuff)
{
if(pBuff)
- // Increment the counter value
+ /* Increment the counter value */
((size_t*)pBuff)[-1]++;
return pBuff;
}
+#ifdef _DEBUG
void _refrelease_dbg(void* pBuff)
{
if(pBuff)
{
- // Decrement the counter value
+ /* Decrement the counter value */
size_t* pMem = (size_t*)pBuff - 2;
assert(pMem[0] == kRefSig);
@@ -93,15 +178,16 @@ void _refrelease_dbg(void* pBuff)
free(pMem);
}
}
+#endif
void _refrelease(void* pBuff)
{
if(pBuff)
{
- // Decrement the counter value
+ /* Decrement the counter value */
size_t* pMem = (size_t*)pBuff - 1;
if(!--pMem[0])
free(pMem);
}
-} \ No newline at end of file
+}
diff --git a/src/ntfs.c b/src/ntfs.c
index 82f6f86..88bab7e 100644
--- a/src/ntfs.c
+++ b/src/ntfs.c
@@ -1,25 +1,21 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
#include "usuals.h"
#include "ntfs.h"
@@ -28,65 +24,66 @@
#include "string.h"
-NTFS_AttribHeader* NTFS_SearchAttribute(byte* pLocation, uint32 attrType, void* pEnd, bool bSkip)
+ntfs_attribheader* ntfs_searchattribute(byte* location, uint32 attrType, byte* end, bool skip)
{
- // Now we should be at attributes
- while((!pEnd || (pLocation + sizeof(NTFS_AttribHeader) < pEnd)) &&
- *((uint32*)pLocation) != kNTFS_RecEnd)
+ /* Now we should be at attributes */
+ while((!end || (location + sizeof(ntfs_attribheader) < end)) &&
+ *((uint32*)location) != kNTFS_RecEnd)
{
- NTFS_AttribHeader* pAttrib = (NTFS_AttribHeader*)pLocation;
+ ntfs_attribheader* attrib = (ntfs_attribheader*)location;
- if(!bSkip)
+ if(!skip)
{
- if(pAttrib->type == attrType)
- return pAttrib;
+ if(attrib->type == attrType)
+ return attrib;
}
else
- bSkip = false;
+ skip = false;
- pLocation += pAttrib->cbAttribute;
+ location += attrib->cbAttribute;
}
return NULL;
}
-byte* NTFS_GetAttributeList(NTFS_RecordHeader* pRecord)
+byte* ntfs_getattributelist(ntfs_recordheader* record)
{
- byte* pLocation = (byte*)pRecord;
- ASSERT(pRecord->x_offUpdSeqArr != 0);
- ASSERT(pRecord->x_offUpdSeqArr < 0x100);
- pLocation += pRecord->x_offUpdSeqArr;
- return pLocation;
+ byte* location = (byte*)record;
+ ASSERT(record->offAttrs != 0);
+ ASSERT(record->offAttrs < 0x100);
+ location += record->offAttrs;
+ return location;
}
-NTFS_AttribHeader* NTFS_FindAttribute(NTFS_RecordHeader* pRecord, uint32 attrType, void* pEnd)
+ntfs_attribheader* ntfs_findattribute(ntfs_recordheader* record, uint32 attrType, byte* end)
{
- byte* pLocation = NTFS_GetAttributeList(pRecord);
-
- return NTFS_SearchAttribute(pLocation, attrType, pEnd, false);
+ byte* location = ntfs_getattributelist(record);
+ return ntfs_searchattribute(location, attrType, end, false);
}
-NTFS_AttribHeader* NTFS_NextAttribute(NTFS_AttribHeader* pAttrib, uint32 attrType, void* pEnd)
+ntfs_attribheader* ntfs_nextattribute(ntfs_attribheader* attrib, uint32 attrType, byte* end)
{
- return NTFS_SearchAttribute((byte*)pAttrib, attrType, pEnd, true);
+ return ntfs_searchattribute((byte*)attrib, attrType, end, true);
}
-void* NTFS_GetAttributeData(NTFS_AttribResident* pAttrib, void* pEnd)
+byte* ntfs_getattributedata(ntfs_attribresident* attrib, byte* end)
{
- void* pData = ((byte*)pAttrib) + pAttrib->offAttribData;
- if(!pEnd && pData > pEnd)
+ byte* data = ((byte*)attrib) + attrib->offAttribData;
+ if(data > end)
return NULL;
- return pData;
+ return data;
}
-bool NTFS_IsBetterNameSpace(byte n1, byte n2)
+bool ntfs_isbetternamespace(byte n1, byte n2)
{
- // We like our namespaces in this order
- // 1. WIN32
- // 2. WIN32/DOS
- // 3. DOS
- // 4. POSIX
+ /*
+ * We like our namespaces in this order
+ * 1. WIN32
+ * 2. WIN32/DOS
+ * 3. DOS
+ * 4. POSIX
+ */
if(n1 == kNTFS_NameSpacePOSIX)
return true;
@@ -100,30 +97,35 @@ bool NTFS_IsBetterNameSpace(byte n1, byte n2)
return false;
}
-bool NTFS_DoFixups(byte* pCluster, uint32 cbCluster)
+bool ntfs_dofixups(byte* cluster, uint32 size)
{
- ASSERT(cbCluster % kSectorSize == 0);
- NTFS_RecordHeader* pRecord = (NTFS_RecordHeader*)pCluster;
+ ntfs_recordheader* record = (ntfs_recordheader*)cluster;
+ byte numSectors;
+ uint16* updSeq;
+ uint16* sectorFooter;
+ byte i;
- byte numSectors = (byte)(cbCluster / kSectorSize);
+ ASSERT(size % kSectorSize == 0);
+ numSectors = (byte)(size / kSectorSize);
- // Check the number of sectors against array
- if(pRecord->cwUpdSeq - 1 < numSectors)
- numSectors = pRecord->cwUpdSeq - 1;
+ /* Check the number of sectors against array */
+ if(record->cwUpdSeq - 1 < numSectors)
+ numSectors = record->cwUpdSeq - 1;
- uint16* pUpdSeq = (uint16*)(pCluster + pRecord->offUpdSeq);
+ updSeq = (uint16*)(cluster + record->offUpdSeq);
- for(byte i = 0; i < numSectors; i++)
+ for(i = 0; i < numSectors; i++)
{
- // Check last 2 bytes in each sector against
- // first double byte value in update sequence
- uint16* pSectorFooter = (uint16*)((pCluster + (kSectorSize - 2)) + (i * kSectorSize));
- if(*pSectorFooter == pUpdSeq[0])
- *pSectorFooter = pUpdSeq[i + 1];
+ /*
+ * Check last 2 bytes in each sector against
+ * first double byte value in update sequence
+ */
+ sectorFooter = (uint16*)((cluster + (kSectorSize - 2)) + (i * kSectorSize));
+ if(*sectorFooter == updSeq[0])
+ *sectorFooter = updSeq[i + 1];
else
return false;
}
return true;
}
-
diff --git a/src/ntfs.h b/src/ntfs.h
index 59a129b..0e5449b 100644
--- a/src/ntfs.h
+++ b/src/ntfs.h
@@ -1,24 +1,21 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
#ifndef __NTFS_H__
#define __NTFS_H__
@@ -31,173 +28,167 @@
#pragma pack(1)
-// WARNING Assumptions:
-const uint32 kNTFS_RecordLen = 0x0400;
+/* WARNING Assumptions: */
+#define kNTFS_RecordLen 0x0400
+#define kNTFS_SysId "NTFS "
-const char kNTFS_SysId[] = "NTFS ";
-
-struct NTFS_BootSector
+typedef struct ntfs_bootsector
{
- byte jmp[3]; // Jump to the boot loader routine
- char sysId[8]; // System Id: "NTFS "
- uint16 bytePerSec; // Bytes per sector
- byte secPerClus; // Sectors per cluster
- byte padding[7]; // Unused
- byte mediaDescriptor; // Media descriptor (a)
- byte padding2[2]; // Unused
- uint16 secPerTrack; // Sectors per track
- uint16 numHeads; // Number of heads
- byte padding3[8]; // Unused
- uint32 signature; // Always 80 00 80 00
- uint64 cSectors; // Number of sectors in the volume
- uint64 offMFT; // LCN of VCN 0 of the $MFT
- uint64 offMFTMirr; // LCN of VCN 0 of the $MFTMirr
- uint32 clusPerMFT; // Clusters per MFT Record (b)
- uint32 clusPerIndex; // Clusters per Index Record
- uint64 serialNum; // Volume serial number
-};
-
-const uint32 kNTFS_RecMagic = 'ELIF';
-const uint32 kNTFS_RecEnd = 0xFFFFFFFF;
-const uint32 kNTFS_RecHeaderLen = 0x30;
-
-const uint16 kNTFS_RecFlagUse = 0x01;
-const uint16 kNTFS_RecFlagDir = 0x02;
-
-struct NTFS_RecordHeader
+ byte jmp[3]; /* Jump to the boot loader routine */
+ char sysId[8]; /* System Id: "NTFS " */
+ uint16 bytePerSec; /* Bytes per sector */
+ byte secPerClus; /* Sectors per cluster */
+ byte padding[7]; /* Unused */
+ byte mediaDescriptor; /* Media descriptor (a) */
+ byte padding2[2]; /* Unused */
+ uint16 secPerTrack; /* Sectors per track */
+ uint16 numHeads; /* Number of heads */
+ byte padding3[8]; /* Unused */
+ uint32 signature; /* Always 80 00 80 00 */
+ uint64 cSectors; /* Number of sectors in the volume */
+ uint64 offMFT; /* LCN of VCN 0 of the $MFT */
+ uint64 offMFTMirr; /* LCN of VCN 0 of the $MFTMirr */
+ uint32 clusPerMFT; /* Clusters per MFT Record (b) */
+ uint32 clusPerIndex; /* Clusters per Index Record */
+ uint64 serialNum; /* Volume serial number */
+}
+ntfs_bootsector;
+
+#define kNTFS_RecMagic ((uint32)'ELIF')
+#define kNTFS_RecEnd 0xFFFFFFFF
+#define kNTFS_RecHeaderLen 0x30
+
+#define kNTFS_RecFlagUse 0x01
+#define kNTFS_RecFlagDir 0x02
+
+typedef struct _ntfs_recordheader
{
- uint32 magic; // Magic number 'FILE'
- uint16 offUpdSeq; // Offset to the update sequence
- uint16 cwUpdSeq; // Size in words of Update Sequence Number & Array (S)
- uint64 logSeqNum; // $LogFile Sequence Number (LSN)
- uint16 seqNum; // Sequence number
- uint16 cHardlinks; // Hard link count
- uint16 x_offUpdSeqArr; // Offset to Update Sequence Array (DON'T THINK SO)
- uint16 flags; // Flags
- uint32 cbRecord; // Real size of the FILE record
- uint32 cbAllocated; // Allocated size of the FILE record
- uint64 refBaseRecord; // File reference to the base FILE record
- uint16 nextAttrId; // Next Attribute Id
- uint16 padding; // (XP) Align to 4 byte boundary
- uint32 recordNum; // (XP) Number of this MFT Record
-};
-
-
-
-const uint16 kNTFS_AttrCompressed = 0x0001;
-const uint16 kNTFS_AttrEncrypted = 0x0002;
-const uint16 kNTFS_AttrSparse = 0x0004;
-
-struct NTFS_AttribHeader
+ uint32 magic; /* Magic number 'FILE' */
+ uint16 offUpdSeq; /* Offset to the update sequence */
+ uint16 cwUpdSeq; /* Size in words of Update Sequence Number & Array (S) */
+ uint64 logSeqNum; /* $LogFile Sequence Number (LSN) */
+ uint16 seqNum; /* Sequence number */
+ uint16 cHardlinks; /* Hard link count */
+ uint16 offAttrs; /* Offset to Attributes */
+ uint16 flags; /* Flags */
+ uint32 cbRecord; /* Real size of the FILE record */
+ uint32 cbAllocated; /* Allocated size of the FILE record */
+ uint64 refBaseRecord; /* File reference to the base FILE record */
+ uint16 nextAttrId; /* Next Attribute Id */
+ uint16 padding; /* (XP) Align to 4 byte boundary */
+ uint32 recordNum; /* (XP) Number of this MFT Record */
+}
+ntfs_recordheader;
+
+
+#define kNTFS_AttrCompressed 0x0001
+#define kNTFS_AttrEncrypted 0x0002
+#define kNTFS_AttrSparse 0x0004
+
+typedef struct _ntfs_attribheader
{
- uint32 type; // Attribute Type (e.g. 0x10, 0x60)
- uint32 cbAttribute; // Length (including this header)
- byte bNonResident; // Non-resident flag
- byte cName; // Name length
- uint16 offName; // Offset to the Attribute
- uint16 flags; // Flags
- uint16 idAttribute; // Attribute Id (a)
-};
-
-struct NTFS_AttribResident
+ uint32 type; /* Attribute Type (e.g. 0x10, 0x60) */
+ uint32 cbAttribute; /* Length (including this header) */
+ byte bNonResident; /* Non-resident flag */
+ byte cName; /* Name length */
+ uint16 offName; /* Offset to the Attribute */
+ uint16 flags; /* Flags */
+ uint16 idAttribute; /* Attribute Id (a) */
+}
+ntfs_attribheader;
+
+typedef struct _ntfs_attribresident
{
- NTFS_AttribHeader header;
+ ntfs_attribheader header;
- uint32 cbAttribData; // Length of the Attribute
- uint16 offAttribData; // Offset to the Attribute
- byte bIndexed; // Indexed flag
- byte padding; // 0x00 Padding
-};
-
-struct NTFS_AttribNonResident
+ uint32 cbAttribData; /* Length of the Attribute */
+ uint16 offAttribData; /* Offset to the Attribute */
+ byte bIndexed; /* Indexed flag */
+ byte padding; /* 0x00 Padding */
+}
+ntfs_attribresident;
+
+typedef struct _ntfs_attribnonresident
{
- NTFS_AttribHeader header;
+ ntfs_attribheader header;
- uint64 startVCN; // Starting VCN
- uint64 lastVCN; // Last VCN
- uint16 offDataRuns; // Offset to the Data Runs
- uint16 compUnitSize; // Compression Unit Size (b)
- uint32 padding; // Padding
- uint64 cbAllocated; // Allocated size of the attribute (c)
- uint64 cbAttribData; // Real size of the attribute
- uint64 cbInitData; // Initialized data size of the stream (d)
-};
-
-
-const uint32 kNTFS_ATTRIBUTE_LIST = 0x20;
-const uint32 kNTFS_FILENAME = 0x30;
-const uint32 kNTFS_DATA = 0x80;
-
-
-const uint32 kNTFS_FileReadOnly = 0x0001;
-const uint32 kNTFS_FileHidden = 0x0002;
-const uint32 kNTFS_FileSystem = 0x0004;
-const uint32 kNTFS_FileArchive = 0x0020;
-const uint32 kNTFS_FileDevice = 0x0040;
-const uint32 kNTFS_FileNormal = 0x0080;
-const uint32 kNTFS_FileTemorary = 0x0100;
-const uint32 kNTFS_FileSparse = 0x0200;
-const uint32 kNTFS_FileReparse = 0x0400;
-const uint32 kNTFS_FileCompressed = 0x0800;
-const uint32 kNTFS_FileOffline = 0x1000;
-const uint32 kNTFS_FileNotIndexed = 0x2000;
-const uint32 kNTFS_FileEncrypted = 0x4000;
-
-const byte kNTFS_NameSpacePOSIX = 0x00;
-const byte kNTFS_NameSpaceWIN32 = 0x01;
-const byte kNTFS_NameSpaceDOS = 0x02;
-const byte kNTFS_NameSpaceWINDOS = 0x03;
-
-const wchar_t kNTFS_MFTName[] = L"$MFT";
-
-struct NTFS_AttrFileName
+ uint64 startVCN; /* Starting VCN */
+ uint64 lastVCN; /* Last VCN */
+ uint16 offDataRuns; /* Offset to the Data Runs */
+ uint16 compUnitSize; /* Compression Unit Size (b) */
+ uint32 padding; /* Padding */
+ uint64 cbAllocated; /* Allocated size of the attribute (c) */
+ uint64 cbAttribData; /* Real size of the attribute */
+ uint64 cbInitData; /* Initialized data size of the stream (d) */
+}
+ntfs_attribnonresident;
+
+
+#define kNTFS_ATTRIBUTE_LIST 0x20
+#define kNTFS_FILENAME 0x30
+#define kNTFS_DATA 0x80
+
+
+#define kNTFS_FileReadOnly 0x0001
+#define kNTFS_FileHidden 0x0002
+#define kNTFS_FileSystem 0x0004
+#define kNTFS_FileArchive 0x0020
+#define kNTFS_FileDevice 0x0040
+#define kNTFS_FileNormal 0x0080
+#define kNTFS_FileTemorary 0x0100
+#define kNTFS_FileSparse 0x0200
+#define kNTFS_FileReparse 0x0400
+#define kNTFS_FileCompressed 0x0800
+#define kNTFS_FileOffline 0x1000
+#define kNTFS_FileNotIndexed 0x2000
+#define kNTFS_FileEncrypted 0x4000
+
+#define kNTFS_NameSpacePOSIX 0x00
+#define kNTFS_NameSpaceWIN32 0x01
+#define kNTFS_NameSpaceDOS 0x02
+#define kNTFS_NameSpaceWINDOS 0x03
+
+#define kNTFS_MFTName L"$MFT"
+
+typedef struct _ntfs_attribfilename
{
- uint64 refParent; // File reference to the parent directory.
- uint64 timeCreated; // C Time - File Creation
- uint64 timeAltered; // A Time - File Altered
- uint64 timeModified; // M Time - MFT Changed
- uint64 timeRead; // R Time - File Read
- uint64 cbAllocated; // Allocated size of the file
- uint64 cbFileSize; // Real size of the file
- uint32 flags; // Flags, e.g. Directory, compressed, hidden
- uint32 eaReparse; // Used by EAs and Reparse
- byte cFileName; // Filename length in characters (L)
- byte nameSpace; // Filename namespace
- // File Name comes here
-};
-
-struct NTFS_AttrListRecord
+ uint64 refParent; /* File reference to the parent directory. */
+ uint64 timeCreated; /* C Time - File Creation */
+ uint64 timeAltered; /* A Time - File Altered */
+ uint64 timeModified; /* M Time - MFT Changed */
+ uint64 timeRead; /* R Time - File Read */
+ uint64 cbAllocated; /* Allocated size of the file */
+ uint64 cbFileSize; /* Real size of the file */
+ uint32 flags; /* Flags, e.g. Directory, compressed, hidden */
+ uint32 eaReparse; /* Used by EAs and Reparse */
+ byte cFileName; /* Filename length in characters (L) */
+ byte nameSpace; /* Filename namespace */
+ /* File Name comes here */
+}
+ntfs_attribfilename;
+
+typedef struct _ntfs_attriblistrecord
{
- uint32 type; // Type
- uint16 cbRecord; // Record length
- byte cName; // Name length (N)
- byte offName; // Offset to Name (a)
- uint64 startVCN; // Starting VCN (b)
- uint64 refAttrib; // Base File Reference of the attribute
- uint16 idAttribute; // Attribute Id (c)
- // Attribute name here
-};
+ uint32 type; /* Type */
+ uint16 cbRecord; /* Record length */
+ byte cName; /* Name length (N) */
+ byte offName; /* Offset to Name (a)*/
+ uint64 startVCN; /* Starting VCN (b) */
+ uint64 refAttrib; /* Base File Reference of the attribute */
+ uint16 idAttribute; /* Attribute Id (c) */
+ /* Attribute name here */
+}
+ntfs_attriblistrecord;
#pragma pack(pop, ntfs)
-NTFS_AttribHeader* NTFS_FindAttribute(NTFS_RecordHeader* pRecord, uint32 attrType, void* pEnd);
-NTFS_AttribHeader* NTFS_NextAttribute(NTFS_AttribHeader* pAttrib, uint32 attrType, void* pEnd);
-
-void* NTFS_GetAttributeData(NTFS_AttribResident* pAttrib, void* pEnd);
-bool NTFS_IsBetterNameSpace(byte n1, byte n2);
-bool NTFS_DoFixups(byte* pCluster, uint32 cbCluster);
-
-
-#define NTFS_RefToSector(info, ref) (((ref & 0xFFFFFFFFFFFF) * (kNTFS_RecordLen / kSectorSize)) + (info).firstSector + (info).offMFT)
-#define NTFS_MakeFileTime(i64, ft) ((ft).dwLowDateTime = LOWDWORD(i64), (ft).dwHighDateTime = HIGHDWORD(i64))
-
-
+ntfs_attribheader* ntfs_findattribute(ntfs_recordheader* record, uint32 attrType, byte* end);
+ntfs_attribheader* ntfs_nextattribute(ntfs_attribheader* attrib, uint32 attrType, byte* end);
+byte* ntfs_getattributelist(ntfs_recordheader* record);
+byte* ntfs_getattributedata(ntfs_attribresident* attrib, byte* end);
-//
-// The record, attribute or whatever was invalid on disk
-//
-#define ERROR_NTFS_INVALID 10801L
-#define ERROR_NTFS_NOTIMPLEMENT 10802L
+bool ntfs_isbetternamespace(byte n1, byte n2);
+bool ntfs_dofixups(byte* cluster, uint32 size);
-#endif //__NTFS_H__ \ No newline at end of file
+#endif /* __NTFS_H__ */
diff --git a/src/ntfsx.c b/src/ntfsx.c
index b2f8a9f..8910f89 100644
--- a/src/ntfsx.c
+++ b/src/ntfsx.c
@@ -1,391 +1,492 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
-// ntfsx.cpp: implementation of the NTFS_Record class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#include "stdafx.h"
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#include <io.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "scrounge.h"
+#include "memref.h"
#include "ntfs.h"
#include "ntfsx.h"
-#include "scrounge.h"
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
+ntfsx_datarun* ntfsx_datarun_alloc(byte* mem, byte* datarun)
+{
+ ntfsx_datarun* dr = (ntfsx_datarun*)malloc(sizeof(ntfsx_datarun));
+ if(dr)
+ {
+ ASSERT(datarun);
+ dr->_mem = (byte*)refadd(mem);
+ dr->_datarun = datarun;
+ dr->_curpos = NULL;
+
+ dr->cluster = 0;
+ dr->length = 0;
+ dr->sparse = false;
+ }
+
+ return dr;
+}
-bool NTFS_Cluster::New(PartitionInfo* pInfo)
+void ntfsx_datarun_free(ntfsx_datarun* dr)
{
- Free();
+ if(dr->_mem)
+ {
+ refrelease(dr->_mem);
+ dr->_mem = NULL;
+ }
- m_cbCluster = CLUSTER_SIZE(*pInfo);
+ free(dr);
+}
- m_pCluster = (byte*)refalloc(m_cbCluster);
- return m_pCluster != NULL;
+bool ntfsx_datarun_first(ntfsx_datarun* dr)
+{
+ dr->_curpos = dr->_datarun;
+ dr->cluster = 0;
+ dr->length = 0;
+ dr->sparse = false;
+ return ntfsx_datarun_next(dr);
}
-bool NTFS_Cluster::Read(PartitionInfo* pInfo, uint64 begSector, HANDLE hIn)
+bool ntfsx_datarun_next(ntfsx_datarun* dr)
{
- if(!m_pCluster)
- {
- if(!New(pInfo))
- return false;
- }
+ byte length;
+ byte roffset;
+ int64 offset;
- // Read the mftRecord
- uint64 offRecord = SECTOR_TO_BYTES(begSector);
- LONG lHigh = HIGHDWORD(offRecord);
- if(SetFilePointer(hIn, LOWDWORD(offRecord), &lHigh, FILE_BEGIN) == -1
- && GetLastError() != NO_ERROR)
- {
- Free();
+ ASSERT(dr->_curpos);
+
+ if(!*(dr->_curpos))
return false;
- }
- DWORD dwRead = 0;
- if(!ReadFile(hIn, m_pCluster, m_cbCluster, &dwRead, NULL) ||
- dwRead != m_cbCluster)
- {
- Free();
- ::SetLastError(ERROR_READ_FAULT);
+ length = *(dr->_curpos) & 0x0F;
+ roffset = *(dr->_curpos) >> 4;
+
+ /* ASSUMPTION: length and offset are less 64 bit numbers */
+ if(length == 0 || length > 8 || roffset > 8)
return false;
+
+ ASSERT(length <= 8);
+ ASSERT(roffset <= 8);
+
+ (dr->_curpos)++;
+
+ memset(&(dr->length), 0, sizeof(uint64));
+
+ memcpy(&(dr->length), (dr->_curpos), length);
+ (dr->_curpos) += length;
+
+
+ /* Note that offset can be negative */
+ if(*((dr->_curpos) + (roffset - 1)) & 0x80)
+ memset(&offset, ~0, sizeof(int64));
+ else
+ memset(&offset, 0, sizeof(int64));
+
+ memcpy(&offset, (dr->_curpos), roffset);
+ (dr->_curpos) += roffset;
+
+ if(offset == 0)
+ {
+ dr->sparse = true;
+ }
+ else
+ {
+ dr->sparse = false;
+ dr->cluster += offset;
}
- ::SetLastError(ERROR_SUCCESS);
return true;
}
-void NTFS_Cluster::Free()
-{
- if(m_pCluster)
- refrelease(m_pCluster);
-
- m_pCluster = NULL;
-}
-NTFS_Record::NTFS_Record(PartitionInfo* pInfo)
-{
- m_pInfo = (PartitionInfo*)refadd(pInfo);
-}
-NTFS_Record::~NTFS_Record()
+
+
+
+bool ntfsx_cluster_reserve(ntfsx_cluster* clus, partitioninfo* info)
{
- refrelease(m_pInfo);
+ ntfsx_cluster_release(clus);
+ clus->size = CLUSTER_SIZE(*info);
+
+ ASSERT(clus->size != 0);
+ clus->data = (byte*)refalloc(clus->size);
+ if(!clus->data)
+ {
+ errno = ENOMEM;
+ return false;
+ }
+
+ return true;
}
-bool NTFS_Record::Read(uint64 begSector, HANDLE hIn)
+bool ntfsx_cluster_read(ntfsx_cluster* clus, partitioninfo* info, uint64 begSector, int dd)
{
- if(!NTFS_Cluster::Read(m_pInfo, begSector, hIn))
- return false;
+ int64 pos;
+ size_t sz;
- // Check and validate this record
- NTFS_RecordHeader* pRecord = GetHeader();
- if(pRecord->magic != kNTFS_RecMagic ||
- !NTFS_DoFixups(m_pCluster, m_cbCluster))
- {
- NTFS_Cluster::Free();
- ::SetLastError(ERROR_NTFS_INVALID);
- return false;
- }
+ if(!clus->data)
+ {
+ if(!ntfsx_cluster_reserve(clus, info))
+ return false;
+ }
+
+ pos = SECTOR_TO_BYTES(begSector);
+ if(_lseeki64(dd, pos, SEEK_SET) == -1)
+ return false;
+
+ sz = read(dd, clus->data, clus->size);
+ if(sz == -1)
+ return false;
+
+ if(sz != clus->size)
+ {
+ errno = ERANGE;
+ return false;
+ }
return true;
}
-NTFS_Attribute* NTFS_Record::FindAttribute(uint32 attrType, HANDLE hIn)
+void ntfsx_cluster_release(ntfsx_cluster* clus)
{
- NTFS_Attribute* pAttribute = NULL;
+ if(clus->data)
+ refrelease(clus->data);
- // Make sure we have a valid record
- ASSERT(GetHeader());
- NTFS_AttribHeader* pHeader = NTFS_FindAttribute(GetHeader(), attrType, (m_pCluster + m_cbCluster));
+ clus->data = NULL;
+ clus->size = 0;
+}
- if(pHeader)
- {
- pAttribute = new NTFS_Attribute(*this, pHeader);
- }
- else
- {
- // Do attribute list thing here!
- pHeader = NTFS_FindAttribute(GetHeader(), kNTFS_ATTRIBUTE_LIST, (m_pCluster + m_cbCluster));
- // For now we only support Resident Attribute lists
- if(hIn && pHeader && !pHeader->bNonResident)
- {
- NTFS_AttribResident* pResident = (NTFS_AttribResident*)pHeader;
- NTFS_AttrListRecord* pAttr = (NTFS_AttrListRecord*)((byte*)pHeader + pResident->offAttribData);
- // Go through AttrList records looking for this attribute
- while((byte*)pAttr < (byte*)pHeader + pHeader->cbAttribute)
- {
- // Found it!
- if(pAttr->type == attrType)
- {
- // Read in appropriate cluster
- uint64 mftRecord = NTFS_RefToSector(*m_pInfo, pAttr->refAttrib);
- NTFS_Record recAttr(m_pInfo);
- if(recAttr.Read(mftRecord, hIn))
- {
- pAttribute = recAttr.FindAttribute(attrType, hIn);
- break;
- }
+ntfsx_attribute* ntfsx_attribute_alloc(ntfsx_cluster* clus, ntfs_attribheader* header)
+{
+ ntfsx_attribute* attr = (ntfsx_attribute*)malloc(sizeof(ntfsx_attribute));
+ if(attr)
+ {
+ attr->_header = header;
+ attr->_mem = (byte*)refadd(clus->data);
+ attr->_length = clus->size;
+ }
- }
+ return attr;
+}
- pAttr = (NTFS_AttrListRecord*)((byte*)pAttr + pAttr->cbRecord);
- }
- }
- }
+void ntfsx_attribute_free(ntfsx_attribute* attr)
+{
+ if(attr->_mem)
+ {
+ refrelease(attr->_mem);
+ attr->_mem = NULL;
+ }
- return pAttribute;
+ free(attr);
}
-bool NTFS_Attribute::NextAttribute(uint32 attrType)
+ntfs_attribheader* ntfsx_attribute_header(ntfsx_attribute* attr)
{
- NTFS_AttribHeader* pHeader = NTFS_NextAttribute(GetHeader(), attrType, m_pMem + m_cbMem);
- if(pHeader)
- {
- m_pHeader = pHeader;
- return true;
- }
-
- return false;
+ return attr->_header;
}
-NTFS_Attribute::NTFS_Attribute(NTFS_Cluster& clus, NTFS_AttribHeader* pHeader)
+void* ntfsx_attribute_getresidentdata(ntfsx_attribute* attr)
{
- m_pHeader = pHeader;
- m_pMem = clus.m_pCluster;
- m_cbMem = clus.m_cbCluster;
- refadd(m_pMem);
+ ntfs_attribresident* res = (ntfs_attribresident*)attr->_header;
+ ASSERT(!attr->_header->bNonResident);
+ return (byte*)(attr->_header) + res->offAttribData;
}
-void* NTFS_Attribute::GetResidentData()
+uint32 ntfsx_attribute_getresidentsize(ntfsx_attribute* attr)
{
- ASSERT(!m_pHeader->bNonResident);
- NTFS_AttribResident* pRes = (NTFS_AttribResident*)m_pHeader;
- return (byte*)m_pHeader + pRes->offAttribData;
+ ntfs_attribresident* res = (ntfs_attribresident*)attr->_header;
+ ASSERT(!attr->_header->bNonResident);
+ return res->cbAttribData;
}
-uint32 NTFS_Attribute::GetResidentSize()
+ntfsx_datarun* ntfsx_attribute_getdatarun(ntfsx_attribute* attr)
{
- ASSERT(!m_pHeader->bNonResident);
- NTFS_AttribResident* pRes = (NTFS_AttribResident*)m_pHeader;
- return pRes->cbAttribData;
+ ntfs_attribnonresident* nonres = (ntfs_attribnonresident*)attr->_header;
+ ASSERT(attr->_header->bNonResident);
+ return ntfsx_datarun_alloc(attr->_mem, (byte*)(attr->_header) + nonres->offDataRuns);
}
-NTFS_DataRun* NTFS_Attribute::GetDataRun()
+bool ntfsx_attribute_next(ntfsx_attribute* attr, uint32 attrType)
{
- ASSERT(m_pHeader->bNonResident);
- NTFS_AttribNonResident* pNonRes = (NTFS_AttribNonResident*)m_pHeader;
+ ntfs_attribheader* header = ntfs_nextattribute(attr->_header, attrType,
+ attr->_mem + attr->_length);
+ if(header)
+ {
+ attr->_header = header;
+ return true;
+ }
- return new NTFS_DataRun(m_pMem, (byte*)m_pHeader + pNonRes->offDataRuns);
+ return false;
}
-NTFS_DataRun::NTFS_DataRun(byte* pClus, byte* pDataRun)
+
+ntfsx_record* ntfsx_record_alloc(partitioninfo* info)
{
- ASSERT(pDataRun);
- m_pMem = (byte*)refadd(pClus);
- m_pDataRun = pDataRun;
- m_pCurPos = NULL;
- m_firstCluster = m_numClusters = 0;
- m_bSparse = false;
+ ntfsx_record* rec = (ntfsx_record*)malloc(sizeof(ntfsx_record));
+ if(rec)
+ {
+ rec->info = info;
+ memset(&(rec->_clus), 0, sizeof(ntfsx_cluster));
+ }
+
+ return rec;
}
-bool NTFS_DataRun::First()
+void ntfsx_record_free(ntfsx_record* record)
{
- m_pCurPos = m_pDataRun;
- m_firstCluster = m_numClusters = 0;
- m_bSparse = false;
- return Next();
+ ntfsx_cluster_release(&(record->_clus));
+ free(record);
}
-bool NTFS_DataRun::Next()
+bool ntfsx_record_read(ntfsx_record* record, uint64 begSector, int dd)
{
- ASSERT(m_pCurPos);
+ ntfs_recordheader* rechead;
- if(!*m_pCurPos)
- return false;
+ if(!ntfsx_cluster_read(&(record->_clus), record->info, begSector, dd))
+ err(1, "couldn't read mft record from drive");
- byte cbLen = *m_pCurPos & 0x0F;
- byte cbOff = *m_pCurPos >> 4;
+ /* Check and validate this record */
+ rechead = ntfsx_record_header(record);
+ if(rechead->magic != kNTFS_RecMagic ||
+ !ntfs_dofixups(record->_clus.data, record->_clus.size))
+ {
+ warnx("invalid mft record");
+ ntfsx_cluster_release(&(record->_clus));
+ return false;
+ }
- // ASSUMPTION length and offset are less 64 bit numbers
- if(cbLen == 0 || cbLen > 8 || cbOff > 8)
- return false;
-
- ASSERT(cbLen <= 8);
- ASSERT(cbOff <= 8);
+ return true;
+}
- m_pCurPos++;
+ntfs_recordheader* ntfsx_record_header(ntfsx_record* record)
+{
+ return (ntfs_recordheader*)(record->_clus.data);
+}
- memset(&m_numClusters, 0, sizeof(uint64));
+ntfsx_attribute* ntfsx_record_findattribute(ntfsx_record* record, uint32 attrType, int dd)
+{
+ ntfsx_attribute* attr = NULL;
+ ntfs_attribheader* attrhead;
+ ntfs_attriblistrecord* atlr;
+ ntfs_attribresident* resident;
+ uint64 mftRecord;
+ ntfsx_record* r2;
+
+ /* Make sure we have a valid record */
+ ASSERT(ntfsx_record_header(record));
+ attrhead = ntfs_findattribute(ntfsx_record_header(record),
+ attrType, (record->_clus.data) + (record->_clus.size));
+
+ if(attrhead)
+ {
+ attr = ntfsx_attribute_alloc(&(record->_clus), attrhead);
+ }
+ else
+ {
+ /* Do attribute list thing here! */
+ attrhead = ntfs_findattribute(ntfsx_record_header(record), kNTFS_ATTRIBUTE_LIST,
+ (record->_clus.data) + (record->_clus.size));
- memcpy(&m_numClusters, m_pCurPos, cbLen);
- m_pCurPos += cbLen;
+ /* For now we only support Resident Attribute lists */
+ if(dd && attrhead && !attrhead->bNonResident && record->info->mftmap)
+ {
+ resident = (ntfs_attribresident*)attrhead;
+ atlr = (ntfs_attriblistrecord*)((byte*)attrhead + resident->offAttribData);
- int64 offset;
+ /* Go through AttrList records looking for this attribute */
+ while((byte*)atlr < (byte*)attrhead + attrhead->cbAttribute)
+ {
+ /* Found it! */
+ if(atlr->type == attrType)
+ {
+ /* Read in appropriate cluster */
+ mftRecord = ntfsx_mftmap_sectorforindex(record->info->mftmap, atlr->refAttrib & 0xFFFFFFFFFFFF);
- // Note that offset can be negative
- if(*(m_pCurPos + (cbOff - 1)) & 0x80)
- memset(&offset, ~0, sizeof(int64));
- else
- memset(&offset, 0, sizeof(int64));
+ r2 = ntfsx_record_alloc(record->info);
+ if(!r2)
+ return NULL;
- memcpy(&offset, m_pCurPos, cbOff);
- m_pCurPos += cbOff;
+ if(ntfsx_record_read(r2, mftRecord, dd))
+ attr = ntfsx_record_findattribute(r2, attrType, dd);
- if(offset == 0)
- {
- m_bSparse = true;
- }
- else
- {
- m_bSparse = false;
- m_firstCluster += offset;
+ ntfsx_record_free(r2);
+
+ if(attr)
+ break;
+ }
+
+ atlr = (ntfs_attriblistrecord*)((byte*)atlr + atlr->cbRecord);
+ }
+ }
}
- return true;
+ return attr;
}
-NTFS_MFTMap::NTFS_MFTMap(PartitionInfo* pInfo)
+
+
+
+struct _ntfsx_mftmap_block
{
- m_pInfo = (PartitionInfo*)refadd(pInfo);
- m_pBlocks = NULL;
- m_count = 0;
-}
+ uint64 firstSector; /* relative to the entire drive */
+ uint64 length; /* length in MFT records */
+};
-NTFS_MFTMap::~NTFS_MFTMap()
+void ntfsx_mftmap_init(ntfsx_mftmap* map, partitioninfo* info)
{
- refrelease(m_pInfo);
+ map->info = info;
+ map->_blocks = NULL;
+ map->_count = 0;
+}
- if(m_pBlocks)
- free(m_pBlocks);
+void ntfsx_mftmap_destroy(ntfsx_mftmap* map)
+{
+ if(map->_blocks)
+ {
+ free(map->_blocks);
+ map->_blocks = NULL;
+ map->_count = 0;
+ }
}
-bool NTFS_MFTMap::Load(NTFS_Record* pRecord, HANDLE hIn)
+bool ntfsx_mftmap_load(ntfsx_mftmap* map, ntfsx_record* record, int dd)
{
- bool bRet = TRUE;
- NTFS_Attribute* pAttribData = NULL; // Data Attribute
- NTFS_DataRun* pDataRun = NULL; // Data runs for nonresident data
+ bool ret = true;
+ ntfsx_attribute* attribdata = NULL; /* Data Attribute */
+ ntfsx_datarun* datarun = NULL; /* Data runs for nonresident data */
{
- printf("[Processing MFT] ");
+ ntfs_attribheader* header;
+ ntfs_attribnonresident* nonres;
+ uint64 length;
+ uint64 firstSector;
+ uint32 allocated;
- // TODO: Check here whether MFT has already been loaded
+ /* TODO: Check here whether MFT has already been loaded */
- // Get the MFT's data
- pAttribData = pRecord->FindAttribute(kNTFS_DATA, hIn);
- if(!pAttribData) RET_ERROR(ERROR_NTFS_INVALID);
+ /* Get the MFT's data */
+ attribdata = ntfsx_record_findattribute(record, kNTFS_DATA, dd);
+ if(!attribdata)
+ RETWARNBX("invalid mft. no data attribute");
- if(!pAttribData->GetHeader()->bNonResident)
- RET_ERROR(ERROR_NTFS_INVALID);
+ header = ntfsx_attribute_header(attribdata);
+ if(!header->bNonResident)
+ RETWARNBX("invalid mft. data attribute non-resident");
- pDataRun = pAttribData->GetDataRun();
- if(!pDataRun)
- RET_ERROR(ERROR_NTFS_INVALID);
+ datarun = ntfsx_attribute_getdatarun(attribdata);
+ if(!datarun)
+ RETWARNBX("invalid mft. no data runs");
- NTFS_AttribNonResident* pNonRes = (NTFS_AttribNonResident*)pAttribData->GetHeader();
+ nonres = (ntfs_attribnonresident*)header;
- if(m_pBlocks)
+ if(map->_blocks)
{
- free(m_pBlocks);
- m_pBlocks = NULL;
+ free(map->_blocks);
+ map->_blocks = NULL;
}
- m_count = 0;
- uint32 allocated = 0;
+ map->_count = 0;
+ allocated = 0;
- // Now loop through the data run
- if(pDataRun->First())
+ /* Now loop through the data run */
+ if(ntfsx_datarun_first(datarun))
{
do
{
- if(pDataRun->m_bSparse)
- RET_ERROR(ERROR_NTFS_INVALID);
+ if(datarun->sparse)
+ RETWARNBX("invalid mft. sparse data runs");
- if(m_count >= allocated)
+ if(map->_count >= allocated)
{
allocated += 16;
- m_pBlocks = (NTFS_Block*)realloc(m_pBlocks, allocated * sizeof(NTFS_Block));
- if(!m_pBlocks)
- RET_FATAL(ERROR_NOT_ENOUGH_MEMORY);
+ map->_blocks = (struct _ntfsx_mftmap_block*)realloc(map->_blocks,
+ allocated * sizeof(struct _ntfsx_mftmap_block));
+ if(!(map->_blocks))
+ errx(1, "out of memory");
}
- uint64 length = pDataRun->m_numClusters * ((m_pInfo->clusterSize * kSectorSize) / kNTFS_RecordLen);
+ ASSERT(map->info->cluster != 0);
+
+ length = datarun->length * ((map->info->cluster * kSectorSize) / kNTFS_RecordLen);
if(length == 0)
continue;
- uint64 firstSector = (pDataRun->m_firstCluster * m_pInfo->clusterSize) + m_pInfo->firstSector;
- if(firstSector >= m_pInfo->lastSector)
+ firstSector = (datarun->cluster * map->info->cluster) + map->info->first;
+ if(firstSector >= map->info->end)
continue;
- m_pBlocks[m_count].length = length;
- m_pBlocks[m_count].firstSector = firstSector;
- m_count++;
+ map->_blocks[map->_count].length = length;
+ map->_blocks[map->_count].firstSector = firstSector;
+ map->_count++;
}
- while(pDataRun->Next());
+ while(ntfsx_datarun_next(datarun));
}
- bRet = true;
- ::SetLastError(ERROR_SUCCESS);
+ ret = true;
}
-clean_up:
+cleanup:
- if(pAttribData)
- delete pAttribData;
- if(pDataRun)
- delete pDataRun;
+ if(attribdata)
+ ntfsx_attribute_free(attribdata);
+ if(datarun)
+ ntfsx_datarun_free(datarun);
- return bRet;
+ return ret;
}
-uint64 NTFS_MFTMap::GetLength()
+uint64 ntfsx_mftmap_length(ntfsx_mftmap* map)
{
uint64 length = 0;
+ uint32 i;
- for(uint32 i = 0; i < m_count; i++)
- length += m_pBlocks[i].length;
+ for(i = 0; i < map->_count; i++)
+ length += map->_blocks[i].length;
return length;
}
-uint64 NTFS_MFTMap::SectorForIndex(uint64 index)
+uint64 ntfsx_mftmap_sectorforindex(ntfsx_mftmap* map, uint64 index)
{
- for(uint32 i = 0; i < m_count; i++)
+ uint32 i;
+ struct _ntfsx_mftmap_block* p;
+ uint64 sector;
+
+ for(i = 0; i < map->_count; i++)
{
- NTFS_Block* p = m_pBlocks + i;
+ p = map->_blocks + i;
- if(index > p->length)
+ if(index >= p->length)
{
index -= p->length;
}
else
{
- uint64 sector = index * (kNTFS_RecordLen / kSectorSize);
+ sector = index * (kNTFS_RecordLen / kSectorSize);
sector += p->firstSector;
- if(sector > m_pInfo->lastSector)
+ if(sector >= map->info->end)
return kInvalidSector;
return sector;
diff --git a/src/ntfsx.h b/src/ntfsx.h
index 836f010..04ebabd 100644
--- a/src/ntfsx.h
+++ b/src/ntfsx.h
@@ -1,139 +1,112 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
-
-// ntfsx
-//
-//////////////////////////////////////////////////////////////////////
-
-#if !defined(AFX_NTFSX__9363C7D2_D3CC_4D49_BEE0_27AD025670F2__INCLUDED_)
-#define AFX_NTFSX__9363C7D2_D3CC_4D49_BEE0_27AD025670F2__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#ifndef __NTFSX_H__
+#define __NTFSX_H__
+
+#include "drive.h"
#include "ntfs.h"
-class NTFS_DataRun
-{
-public:
- NTFS_DataRun(byte* pClus, byte* pDataRun);
- ~NTFS_DataRun()
- { refrelease(m_pMem); }
-
- bool First();
- bool Next();
-
- uint64 m_firstCluster;
- uint64 m_numClusters;
- bool m_bSparse;
-protected:
- byte* m_pMem;
- byte* m_pDataRun;
- byte* m_pCurPos;
-};
-
-class NTFS_Cluster
+/* used as a heap based object */
+typedef struct _ntfsx_datarun
{
-public:
- NTFS_Cluster()
- { m_pCluster = NULL; };
- ~NTFS_Cluster()
- { Free(); }
+ byte* _mem; /* ref counted */
+ byte* _datarun;
+ byte* _curpos;
- bool New(PartitionInfo* pInfo);
- bool Read(PartitionInfo* pInfo, uint64 begSector, HANDLE hIn);
- void Free();
+ bool sparse;
+ uint64 cluster;
+ uint64 length;
+}
+ntfsx_datarun;
-
- uint32 m_cbCluster;
- byte* m_pCluster;
-};
-
-class NTFS_Attribute
-{
-public:
- NTFS_Attribute(NTFS_Cluster& clus, NTFS_AttribHeader* pHeader);
- ~NTFS_Attribute()
- { refrelease(m_pMem); }
+ntfsx_datarun* ntfsx_datarun_alloc(byte* mem, byte* datarun);
+void ntfsx_datarun_free(ntfsx_datarun* dr);
+bool ntfsx_datarun_first(ntfsx_datarun* dr);
+bool ntfsx_datarun_next(ntfsx_datarun* dr);
- NTFS_AttribHeader* GetHeader()
- { return m_pHeader; }
- void* GetResidentData();
- uint32 GetResidentSize();
-
- NTFS_DataRun* GetDataRun();
-
- bool NextAttribute(uint32 attrType);
+/* used as a stack based object */
+typedef struct _ntfsx_cluster
+{
+ uint32 size;
+ byte* data; /* ref counted */
+}
+ntfsx_cluster;
+
+bool ntfsx_cluster_reserve(ntfsx_cluster* clus, partitioninfo* info);
+bool ntfsx_cluster_read(ntfsx_cluster* clus, partitioninfo* info, uint64 begSector, int dd);
+void ntfsx_cluster_release(ntfsx_cluster* clus);
+
-protected:
- NTFS_AttribHeader* m_pHeader;
- byte* m_pMem;
- uint32 m_cbMem;
-};
-class NTFS_Record :
- public NTFS_Cluster
+/* used as a heap based object */
+typedef struct _ntfsx_attribute
{
-public:
- NTFS_Record(PartitionInfo* pInfo);
- ~NTFS_Record();
+ ntfs_attribheader* _header;
+ byte* _mem; /* ref counted */
+ uint32 _length;
+}
+ntfsx_attribute;
- bool Read(uint64 begSector, HANDLE hIn);
- NTFS_RecordHeader* GetHeader()
- { return (NTFS_RecordHeader*)m_pCluster; }
+ntfsx_attribute* ntfsx_attribute_alloc(ntfsx_cluster* clus, ntfs_attribheader* header);
+void ntfsx_attribute_free(ntfsx_attribute* attr);
+ntfs_attribheader* ntfsx_attribute_header(ntfsx_attribute* attr);
+void* ntfsx_attribute_getresidentdata(ntfsx_attribute* attr);
+uint32 ntfsx_attribute_getresidentsize(ntfsx_attribute* attr);
+ntfsx_datarun* ntfsx_attribute_getdatarun(ntfsx_attribute* attr);
+bool ntfsx_attribute_next(ntfsx_attribute* attr, uint32 attrType);
- NTFS_Attribute* FindAttribute(uint32 attrType, HANDLE hIn);
-protected:
- PartitionInfo* m_pInfo;
-};
-class NTFS_MFTMap
+/* used as a heap based object */
+typedef struct _ntfsx_record
{
-public:
- NTFS_MFTMap(PartitionInfo* pInfo);
- ~NTFS_MFTMap();
+ partitioninfo* info;
+ ntfsx_cluster _clus;
+}
+ntfsx_record;
- bool Load(NTFS_Record* pRecord, HANDLE hIn);
+ntfsx_record* ntfsx_record_alloc(partitioninfo* info);
+void ntfsx_record_free(ntfsx_record* record);
+bool ntfsx_record_read(ntfsx_record* record, uint64 begSector, int dd);
+ntfs_recordheader* ntfsx_record_header(ntfsx_record* record);
+ntfsx_attribute* ntfsx_record_findattribute(ntfsx_record* record, uint32 attrType, int dd);
- uint64 GetLength();
- uint64 SectorForIndex(uint64 index);
-protected:
- PartitionInfo* m_pInfo;
- struct NTFS_Block
- {
- uint64 firstSector; // relative to the entire drive
- uint64 length; // length in MFT records
- };
-
- NTFS_Block* m_pBlocks;
- uint32 m_count;
-};
-
-#endif // !defined(AFX_NTFSX__9363C7D2_D3CC_4D49_BEE0_27AD025670F2__INCLUDED_)
+/* used as a stack based object */
+struct _ntfsx_mftmap_block;
+typedef struct _ntfsx_mftmap
+{
+ partitioninfo* info;
+ struct _ntfsx_mftmap_block* _blocks;
+ uint32 _count;
+}
+ntfsx_mftmap;
+
+void ntfsx_mftmap_init(ntfsx_mftmap* map,partitioninfo* info);
+void ntfsx_mftmap_destroy(ntfsx_mftmap* map);
+bool ntfsx_mftmap_load(ntfsx_mftmap* map, ntfsx_record* record, int dd);
+uint64 ntfsx_mftmap_length(ntfsx_mftmap* map);
+uint64 ntfsx_mftmap_sectorforindex(ntfsx_mftmap* map, uint64 index);
+
+#endif
diff --git a/src/scrounge.c b/src/scrounge.c
index 2cb0d71..f4436de 100644
--- a/src/scrounge.c
+++ b/src/scrounge.c
@@ -1,717 +1,487 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
-// Scrounge.cpp
-//
-
-#include "stdafx.h"
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#include <io.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "scrounge.h"
#include "ntfs.h"
#include "ntfsx.h"
-#include "usuals.h"
-#include "drive.h"
#include "locks.h"
-#include "scrounge.h"
-// ----------------------------------------------------------------------
-// Process a potential MFT Record. For directories create the directory
-// and for files write out the file.
-//
-// Current Directory is the output directory
-// hIn is an open drive handle
-// pInfo is partition info about hIn (needs to be a ref counted pointer)
-
-BOOL ProcessMFTRecord(PartitionInfo* pInfo, uint64 sector, NTFS_MFTMap* map, HANDLE hIn)
+typedef struct _filebasics
{
- // Declare data that needs cleaning up first
- BOOL bRet = TRUE; // Return value
- HANDLE hFile = NULL; // Output file handle
- NTFS_Attribute* pAttribName = NULL; // Filename Attribute
- NTFS_Attribute* pAttribData = NULL; // Data Attribute
- NTFS_DataRun* pDataRun = NULL; // Data runs for nonresident data
-
- ASSERT(sector != kInvalidSector);
-
-
- // Tracks whether or not we output a file
- bool bFile = false;
-
- {
- // Read the MFT record
- NTFS_Record record(pInfo);
- if(!record.Read(sector, hIn))
- PASS_ERROR();
-
- NTFS_RecordHeader* pRecord = record.GetHeader();
-
-
- // Check if this record is in use
- if(!(pRecord->flags & kNTFS_RecFlagUse))
- RET_ERROR(ERROR_SUCCESS);
-
+ wchar_t filename[MAX_PATH + 1];
+ uint64 created;
+ uint64 modified;
+ uint64 accessed;
+ uint32 flags;
+ uint64 parent;
+}
+filebasics;
- // Info that we use later
- WCHAR fileName[MAX_PATH + 1];
- FILETIME ftCreated;
- FILETIME ftModified;
- FILETIME ftAccessed;
- DWORD fileAttrib = 0;
- uint64 mftParent = kInvalidSector;
- byte* pResidentData = NULL;
+void processRecordFileBasics(partitioninfo* pi, ntfsx_record* record, filebasics* basics)
+{
+ /* Data Attribute */
+ ntfsx_attribute* attr = NULL;
+ {
+ byte* resident = NULL;
+ ntfs_attribfilename* filename;
+ byte nameSpace;
- // Now get the name and info...
- pAttribName = record.FindAttribute(kNTFS_FILENAME, hIn);
- if(!pAttribName) RET_ERROR(ERROR_SUCCESS);
+ ASSERT(record);
+ memset(basics, 0, sizeof(filebasics));
+ basics->parent = kInvalidSector;
+ /* Now get the name and info... */
+ attr = ntfsx_record_findattribute(record, kNTFS_FILENAME, pi->device);
+ if(!attr) goto cleanup;
- byte nameSpace = kNTFS_NameSpacePOSIX;
- memset(fileName, 0, sizeof(fileName));
+ nameSpace = kNTFS_NameSpacePOSIX;
+ memset(basics->filename, 0, sizeof(basics->filename));
do
{
- // TODO ASSUMPTION: File name is always resident
- ASSERT(!pAttribName->GetHeader()->bNonResident);
+ /* TODO ASSUMPTION: File name is always resident */
+ ASSERT(!ntfsx_attribute_header(attr)->bNonResident);
- // Get out all the info we need
- NTFS_AttrFileName* pFileName = (NTFS_AttrFileName*)pAttribName->GetResidentData();
+ /* Get out all the info we need */
+ filename = (ntfs_attribfilename*)ntfsx_attribute_getresidentdata(attr);
+ ASSERT(filename);
- // There can be multiple filenames with different namespaces
- // so choose the best one
- if(NTFS_IsBetterNameSpace(nameSpace, pFileName->nameSpace))
+ /*
+ * There can be multiple filenames with different
+ * namespaces so choose the best one
+ */
+ if(ntfs_isbetternamespace(nameSpace, filename->nameSpace))
{
- // Dates
- NTFS_MakeFileTime(pFileName->timeCreated, ftCreated);
- NTFS_MakeFileTime(pFileName->timeModified, ftModified);
- NTFS_MakeFileTime(pFileName->timeRead, ftAccessed);
-
- // File Name
- wcsncpy(fileName, (wchar_t*)(((byte*)pFileName) + sizeof(NTFS_AttrFileName)), pFileName->cFileName);
- fileName[pFileName->cFileName] = 0;
-
- // Attributes
- if(pFileName->flags & kNTFS_FileReadOnly)
- fileAttrib |= FILE_ATTRIBUTE_READONLY;
- if(pFileName->flags & kNTFS_FileHidden)
- fileAttrib |= FILE_ATTRIBUTE_HIDDEN;
- if(pFileName->flags & kNTFS_FileArchive)
- fileAttrib |= FILE_ATTRIBUTE_ARCHIVE;
- if(pFileName->flags & kNTFS_FileSystem)
- fileAttrib |= FILE_ATTRIBUTE_SYSTEM;
-
- // Parent Directory
- if(map)
- mftParent = map->SectorForIndex(pFileName->refParent & 0xFFFFFFFFFFFF);
-
- // Namespace
- nameSpace = pFileName->nameSpace;
+ /* Dates */
+ basics->created = filename->timeCreated;
+ basics->modified = filename->timeModified;
+ basics->accessed = filename->timeRead;
+
+ /* File Name */
+ wcsncpy(basics->filename, (wchar_t*)(((byte*)filename) + sizeof(ntfs_attribfilename)), filename->cFileName);
+ basics->filename[filename->cFileName] = 0;
+
+ /* Attributes */
+ basics->flags = filename->flags;
+
+ /* Parent Directory */
+ basics->parent = filename->refParent & 0xFFFFFFFFFFFF;
+
+ /* Namespace */
+ nameSpace = filename->nameSpace;
}
}
- while(pAttribName->NextAttribute(kNTFS_FILENAME));
+ while(ntfsx_attribute_next(attr, kNTFS_FILENAME));
+ }
+cleanup:
+ if(attr)
+ ntfsx_attribute_free(attr);
+}
- // Check if we got a file name
- if(fileName[0] == 0)
- RET_ERROR(ERROR_NTFS_INVALID);
+void processMFTRecord(partitioninfo* pi, uint64 sector, int level)
+{
+ ntfsx_record* record = NULL;
+ ntfsx_attribute* attribdata = NULL;
+ ntfsx_datarun* datarun = NULL;
+ int outfile = -1;
+ ntfsx_cluster cluster;
+ memset(&cluster, 0, sizeof(cluster));
- // Check if it's the root
- // If so then bumm out cuz we don't want to have anything to do with it
- if(sector == mftParent || // Root is it's own parent
- !wcscmp(fileName, L".")) // Or is called '.'
- RET_ERROR(ERROR_SUCCESS);
+ {
+ filebasics basics;
+ ntfs_recordheader* header;
+ uint64 parentSector;
+ uint64 dataSector;
+ uint16 rename = 0;
+ uint64 fileSize;
+ uint32 i;
+ uint32 num;
+ wchar_t filename2[MAX_PATH + 1];
+ ntfs_attribheader* attrhead;
+ ntfs_attribnonresident* nonres;
+
+ ASSERT(sector != kInvalidSector);
+
+ record = ntfsx_record_alloc(pi);
+ if(!record)
+ errx(1, "out of memory");
+
+ /* Read the MFT record */
+ if(!ntfsx_record_read(record, sector, pi->device))
+ RETURN;
+
+ header = ntfsx_record_header(record);
+ ASSERT(header);
+
+ if(!(header->flags & kNTFS_RecFlagUse))
+ RETURN;
+
+ /* Try and get a file name out of the header */
+ processRecordFileBasics(pi, record, &basics);
+
+ if(basics.filename[0] == 0)
+ {
+ RETWARNX("invalid mft record. in use, but no filename");
+ }
+ /* If it's the root folder then return */
+ if(!wcscmp(basics.filename, L"."))
+ RETURN;
- // If it's the MFT then we read that in
- if(!wcscmp(fileName, kNTFS_MFTName))
+ /* Process parent folders if available */
+ if(basics.parent != kInvalidSector)
{
- if(map)
+ /* Only if we have MFT map info available */
+ if(pi->mftmap)
{
- printf("[Processing MFT] ");
+ parentSector = ntfsx_mftmap_sectorforindex(pi->mftmap, basics.parent);
- // We found the MFT, let's load it up
- if(!map->Load(&record, hIn))
- PASS_FATAL();
+ if(parentSector == kInvalidSector)
+ warnx("invalid parent directory for file: %S", basics.filename);
+ else
+ processMFTRecord(pi, parentSector, level + 1);
}
-
- RET_ERROR(ERROR_SUCCESS);
}
+ printf(level == 0 ? "\\%S\n" : "\\%S", basics.filename);
- if(mftParent != kInvalidSector)
+ /* Directory handling: */
+ if(header->flags & kNTFS_RecFlagDir)
{
- // Create Parent folders
- if(!ProcessMFTRecord(pInfo, mftParent, map, hIn))
- PASS_FATAL();
+ /* Try to change to the directory */
+ /* PORT: Wide character file functions */
+ if(_wchdir(basics.filename) == -1)
+ {
+ /* PORT: Wide character file functions */
+ if(_wmkdir(basics.filename) == -1)
+ {
+ warnx("couldn't create directory '%S' putting files in parent directory", basics.filename);
+ }
+ else
+ {
+ setFileAttributes(basics.filename, basics.flags);
+ _wchdir(basics.filename);
+ }
+ }
+
+ RETURN;
}
- // If it's a folder then create it
- if(pRecord->flags & kNTFS_RecFlagDir)
- {
- // Try to change to dir
- if(!SetCurrentDirectoryW(fileName))
- {
- // Otherwise create dir
- if(CreateDirectoryW(fileName, NULL))
- {
- // And set attributes
- SetFileAttributesW(fileName, fileAttrib);
- SetCurrentDirectoryW(fileName);
- }
- }
+ /* Normal file handling: */
+ /* PORT: Wide character file functions */
+ outfile = _wopen(basics.filename, _O_BINARY | _O_CREAT | _O_EXCL | _O_WRONLY);
+
+ wcsncpy(filename2, basics.filename, MAX_PATH);
+ filename2[MAX_PATH] = 0;
- wprintf(L"\\%s", fileName);
- }
+ while(outfile == -1 && errno == EEXIST && rename < 0x1000)
+ {
+ if(wcslen(basics.filename) + 7 >= MAX_PATH)
+ {
+ warnx("file name too long on duplicate file: %S", basics.filename);
+ goto cleanup;
+ }
+ wcscpy(basics.filename, filename2);
+ wcscat(basics.filename, L".");
- // Otherwise write the file data
- else
- {
- // Write to the File
- hFile = CreateFileW(fileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
+ _itow(rename, basics.filename + wcslen(basics.filename), 10);
+ rename++;
- uint16 nRename = 0;
- wchar_t fileName2[MAX_PATH + 1];
- wcscpy(fileName2, fileName);
+ outfile = _wopen(basics.filename, _O_BINARY | _O_CREAT | _O_EXCL | _O_WRONLY);
+ }
+
+ if(outfile == -1)
+ {
+ warnx("couldn't open output file: %S", basics.filename);
+ goto cleanup;
+ }
- // For duplicate files we add .x to the file name where x is a number
- while(hFile == INVALID_HANDLE_VALUE && ::GetLastError() == ERROR_FILE_EXISTS
- && nRename < 0x1000000)
- {
- wcscpy(fileName, fileName2);
- wcscat(fileName, L".");
- uint16 len = wcslen(fileName);
-
- // Make sure we don't have a buffer overflow
- if(len > MAX_PATH - 5)
- break;
-
- _itow(nRename, fileName + len, 10);
- nRename++;
-
- hFile = CreateFileW(fileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
- }
-
- wprintf(L"\\%s", fileName);
- bFile = true;
- // Check if successful after all that
- if(hFile == INVALID_HANDLE_VALUE)
- PASS_FATAL();
+ attribdata = ntfsx_record_findattribute(record, kNTFS_DATA, pi->device);
+ if(!attribdata)
+ RETWARNX("invalid mft record. no data attribute found");
+
+ attrhead = ntfsx_attribute_header(attribdata);
-
- DWORD dwDone = 0;
- uint64 fileSize = 0;
+ /* For resident data just write it out */
+ if(!attrhead->bNonResident)
+ {
+ uint32 length = ntfsx_attribute_getresidentsize(attribdata);
+ byte* data = ntfsx_attribute_getresidentdata(attribdata);
+ if(!data)
+ RETWARNX("invalid mft record. resident data screwed up");
- // Get the File's data
- pAttribData = record.FindAttribute(kNTFS_DATA, hIn);
- if(!pAttribData) RET_ERROR(ERROR_NTFS_INVALID);
+ if(write(outfile, data, length) != (int32)length)
+ RETWARN("couldn't write data to output file");
+ }
-
- // For Resident data just write it out
- if(!pAttribData->GetHeader()->bNonResident)
- {
- if(!WriteFile(hFile, pAttribData->GetResidentData(), pAttribData->GetResidentSize(), &dwDone, NULL))
- PASS_FATAL();
- }
+ /* For non resident data it's a bit more involved */
+ else
+ {
+ datarun = ntfsx_attribute_getdatarun(attribdata);
+ if(!datarun)
+ errx(1, "out of memory");
- // For Nonresident data a bit more involved
- else
- {
- pDataRun = pAttribData->GetDataRun();
- ASSERT(pDataRun != NULL);
+ nonres = (ntfs_attribnonresident*)attrhead;
+ fileSize = nonres->cbAttribData;
- NTFS_AttribNonResident* pNonRes = (NTFS_AttribNonResident*)pAttribData->GetHeader();
- fileSize = pNonRes->cbAttribData;
+ /* Allocate a cluster for reading and writing */
+ if(!ntfsx_cluster_reserve(&cluster, pi))
+ errx(1, "out of memory");
- // Allocate a cluster for reading and writing
- NTFS_Cluster clus;
- if(!clus.New(pInfo))
- RET_FATAL(ERROR_NOT_ENOUGH_MEMORY);
-
+ if(ntfsx_datarun_first(datarun))
+ {
+ do
+ {
+ /* Check to see if we have a bogus data run */
+ if(fileSize == 0 && datarun->length)
+ {
+ warnx("invalid mft record. file length invalid or extra data in file");
+ break;
+ }
+
+ /* Sparse clusters we just write zeros */
+ if(datarun->sparse)
+ {
+ memset(cluster.data, 0, cluster.size);
+
+ for(i = 0; i < datarun->length && fileSize; i++)
+ {
+ num = cluster.size;
+
+ if(fileSize < 0xFFFFFFFF && num > (uint32)fileSize)
+ num = (uint32)fileSize;
+
+ if(write(outfile, cluster.data, num) != (int32)num)
+ err(1, "couldn't write to output file: %S", basics.filename);
+
+ fileSize -= num;
+ }
+ }
+
+ /* Handle not sparse clusters */
+ else
+ {
+ if(pi->locks)
+ {
+ /* Add a location lock so any raw scrounging won't do
+ this cluster later */
+ addLocationLock(pi->locks, CLUSTER_TO_SECTOR(*pi, datarun->cluster),
+ CLUSTER_TO_SECTOR(*pi, datarun->cluster + datarun->length));
+ }
+
+ for(i = 0; i < datarun->length && fileSize; i++)
+ {
+ num = min(cluster.size, (uint32)fileSize);
+ dataSector = CLUSTER_TO_SECTOR(*pi, (datarun->cluster + i));
+
+ if(!ntfsx_cluster_read(&cluster, pi, dataSector, pi->device))
+ err(1, "couldn't read sector from disk");
+
+ if(write(outfile, cluster.data, num) != (int32)num)
+ err(1, "couldn't write to output file: %S", basics.filename);
+
+ fileSize -= num;
+ }
+ }
+ }
+ while(ntfsx_datarun_next(datarun));
+ }
+ }
- // Now loop through the data run
- if(pDataRun->First())
- {
- do
- {
- // If it's a sparse cluster then just write zeros
- if(pDataRun->m_bSparse)
- {
- memset(clus.m_pCluster, 0, clus.m_cbCluster);
-
- for(uint32 i = 0; i < pDataRun->m_numClusters && fileSize; i++)
- {
- DWORD dwToWrite = clus.m_cbCluster;
- if(!HIGHDWORD(fileSize) && dwToWrite > (DWORD)fileSize)
- dwToWrite = (DWORD)fileSize;
-
- if(!WriteFile(hFile, clus.m_pCluster, dwToWrite, &dwDone, NULL))
- PASS_FATAL();
-
- fileSize -= dwToWrite;
- }
- }
-
- // Not sparse
- else
- {
- // Add a lock on those clusters so we don't have to scrounge'm later
- AddLocationLock(pInfo, CLUSTER_TO_SECTOR(*pInfo, pDataRun->m_firstCluster),
- CLUSTER_TO_SECTOR(*pInfo, pDataRun->m_firstCluster + pDataRun->m_numClusters));
-
- // Read and write clusters out
- for(uint32 i = 0; i < pDataRun->m_numClusters && fileSize; i++)
- {
- DWORD dwToWrite = min(clus.m_cbCluster, (DWORD)fileSize);
- uint64 sector = CLUSTER_TO_SECTOR(*pInfo, (pDataRun->m_firstCluster + i));
-
- if(!clus.Read(pInfo, sector, hIn))
- PASS_ERROR();
-
- if(!WriteFile(hFile, clus.m_pCluster, dwToWrite, &dwDone, NULL))
- PASS_FATAL();
-
- fileSize -= dwToWrite;
- }
- }
- }
- while(pDataRun->Next());
- }
- }
+ if(fileSize != 0)
+ warnx("invalid mft record. couldn't find all data for file");
- // TODO: More intelligence needed here
- if(fileSize != 0)
- printf(" (Entire file not written)");
+ close(outfile);
+ outfile = -1;
- SetFileTime(hFile, &ftCreated, &ftAccessed, &ftModified);
-
- CloseHandle(hFile);
- hFile = NULL;
+ setFileTime(basics.filename, &(basics.created),
+ &(basics.accessed), &(basics.modified));
- SetFileAttributesW(fileName, fileAttrib);
- }
- }
+ setFileAttributes(basics.filename, basics.flags);
+ }
- bRet = TRUE;
- ::SetLastError(ERROR_SUCCESS);
+cleanup:
+ if(record)
+ ntfsx_record_free(record);
-clean_up:
- if(hFile && hFile != INVALID_HANDLE_VALUE)
- CloseHandle(hFile);
- if(pAttribName)
- delete pAttribName;
- if(pAttribData)
- delete pAttribData;
- if(pDataRun)
- delete pDataRun;
+ ntfsx_cluster_release(&cluster);
- if(bFile)
- {
- if(::GetLastError() != ERROR_SUCCESS)
- {
- printf(" (");
- PrintLastError();
- fputc(')', stdout);
- }
- }
+ if(attribdata)
+ ntfsx_attribute_free(attribdata);
+ if(datarun)
+ ntfsx_datarun_free(datarun);
- return bRet;
+ if(outfile != -1)
+ close(outfile);
}
-// ----------------------------------------------------------------------
-// Helper function to print out errors
-
-void PrintLastError()
+void scroungeMFT(partitioninfo* pi, ntfsx_mftmap* map)
{
- DWORD dwErr = ::GetLastError();
- switch(dwErr)
- {
- case ERROR_NTFS_INVALID:
- printf("Invalid NTFS data structure");
- break;
+ ntfsx_record* record = NULL;
+ uint64 sector;
+ filebasics basics;
+ ntfs_recordheader* header;
- case ERROR_NTFS_NOTIMPLEMENT:
- printf("NTFS feature not implemented");
- break;
+ /* Try and find the MFT at the given location */
+ sector = pi->mft + pi->first;
- default:
- {
- LPVOID lpMsgBuf;
-
- DWORD dwRet = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_MAX_WIDTH_MASK,
- NULL,
- dwErr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL);
-
- if(dwRet && lpMsgBuf)
- {
- // Remove return
- ((LPTSTR)lpMsgBuf)[dwRet - 2] = 0;
+ if(sector >= pi->end)
+ errx(2, "invalid mft. past end of partition");
- wprintf((LPTSTR)lpMsgBuf);
+ record = ntfsx_record_alloc(pi);
+ if(!record)
+ errx(1, "out of memory");
- // Free the buffer.
- ::LocalFree(lpMsgBuf);
- }
- }
- };
-}
+ /* Read the MFT record */
+ if(!ntfsx_record_read(record, sector, pi->device))
+ err(1, "couldn't read mft");
+ header = ntfsx_record_header(record);
+ ASSERT(header);
-// ----------------------------------------------------------------------
-// Scrounge the partition for MFT Records and hand off to
-// ProcessMFTRecord for processing
+ if(!(header->flags & kNTFS_RecFlagUse))
+ errx(2, "invalid mft. marked as not in use");
-BOOL ScroungeMFTRecords(PartitionInfo* pInfo, HANDLE hIn)
-{
- uint64 numRecords = 0;
+ /* Try and get a file name out of the header */
- // Save current directory away
- TCHAR curDir[MAX_PATH + 1];
- GetCurrentDirectory(MAX_PATH, curDir);
+ processRecordFileBasics(pi, record, &basics);
- NTFS_MFTMap map(pInfo);
+ if(wcscmp(basics.filename, kNTFS_MFTName))
+ errx(2, "invalid mft. wrong record");
- // Try and find the MFT at the given location
- uint64 sector = pInfo->offMFT + pInfo->firstSector;
+ fprintf(stderr, "[Processing MFT...]\n");
- if(sector < pInfo->lastSector)
- {
- BOOL bRet = ProcessMFTRecord(pInfo, sector, &map, hIn);
+ /* Load the MFT data runs */
- fputc('\n', stdout);
+ if(!ntfsx_mftmap_load(map, record, pi->device))
+ err(1, "error reading in mft");
- if(!bRet)
- return FALSE;
- }
+ if(ntfsx_mftmap_length(map) == 0)
+ errx(1, "invalid mft. no records in mft");
- uint64 length = map.GetLength();
- if(length == 0)
- {
- printf("[MFT not found at specified location. No folder structure]\n");
- return ScroungeRawRecords(pInfo, hIn);
- }
+ ntfsx_record_free(record);
+}
- for(uint64 i = 1; i < length; i += (kNTFS_RecordLen / kSectorSize))
- {
- // Move to right output directory
- SetCurrentDirectory(curDir);
- // TODO: Warn when invalid
- uint64 sector = map.SectorForIndex(i);
+void scroungeUsingMFT(partitioninfo* pi)
+{
+ uint64 numRecords = 0;
+ char dir[MAX_PATH];
+ ntfsx_mftmap map;
+ uint64 length;
+ uint64 sector;
+ uint64 i;
+
+ fprintf(stderr, "[Scrounging via MFT...]\n");
+
+ /* Save current directory away */
+ getcwd(dir, MAX_PATH);
+
+ /* Get the MFT map ready */
+ memset(&map, 0, sizeof(map));
+ ntfsx_mftmap_init(&map, pi);
+ pi->mftmap = &map;
+
+
+ /*
+ * Make sure the MFT is actually where they say it is.
+ * This also fills in the valid cluster size if needed
+ */
+ scroungeMFT(pi, &map);
+ length = ntfsx_mftmap_length(&map);
+
+ for(i = 1; i < length; i ++)
+ {
+ sector = ntfsx_mftmap_sectorforindex(&map, i);
if(sector == kInvalidSector)
+ {
+ warnx("invalid index in mft: %d", i);
continue;
+ }
- // Then process it
- BOOL bRet = ProcessMFTRecord(pInfo, sector, &map, hIn);
-
- fputc('\n', stdout);
+ /* Process the record */
+ processMFTRecord(pi, sector, 0);
- if(!bRet)
- return FALSE;
+ /* Move to right output directory */
+ chdir(dir);
}
- return TRUE;
+ pi->mftmap = NULL;
}
-BOOL ScroungeRawRecords(PartitionInfo* pInfo, HANDLE hIn)
+void scroungeUsingRaw(partitioninfo* pi)
{
byte buffSec[kSectorSize];
- DWORD dwDummy = 0;
+ char dir[_MAX_PATH + 1];
+ uint64 sec;
+ drivelocks locks;
+ int64 pos;
+ size_t sz;
+ uint32 magic = kNTFS_RecMagic;
- uint64 numRecords = 0;
-
- // Save current directory away
- TCHAR curDir[MAX_PATH + 1];
- GetCurrentDirectory(MAX_PATH, curDir);
+ fprintf(stderr, "[Scrounging raw records...]\n");
- // Loop through sectors
- for(uint64 sec = pInfo->firstSector; sec < pInfo->lastSector; sec++)
- {
- // See if the current sector has already been read
- if(CheckLocationLock(pInfo, sec))
- {
- // TODO: check this
- sec--;
- continue;
- }
+ /* Save current directory away */
+ getcwd(dir, _MAX_PATH);
- // Read the mftRecord
- uint64 offRecord = SECTOR_TO_BYTES(sec);
- LONG lHigh = HIGHDWORD(offRecord);
- if(SetFilePointer(hIn, LOWDWORD(offRecord), &lHigh, FILE_BEGIN) == -1
- && GetLastError() != NO_ERROR)
- return FALSE;
+ /* Get the locks ready */
+ memset(&locks, 0, sizeof(locks));
+ pi->locks = &locks;
- if(!ReadFile(hIn, buffSec, kSectorSize, &dwDummy, NULL))
- return FALSE;
-
- // Check beginning of sector for the magic signature
- if(!memcmp(&kNTFS_RecMagic, &buffSec, sizeof(kNTFS_RecMagic)))
- {
- // Move to right output directory
- SetCurrentDirectory(curDir);
-
- // Then process it
- BOOL bRet = ProcessMFTRecord(pInfo, sec, NULL, hIn);
-
- fputc('\n', stdout);
-
- if(!bRet)
- return FALSE;
-
- }
- }
-
- return TRUE;
-}
-
-
-// ----------------------------------------------------------------------
-// Output strings
-
-const char kPrintHeader[] = "Scrounge (NTFS) Version 0.7\n\n";
-
-const char kPrintData[] = "\
- Start Sector End Sector Cluster Size MFT Offset \n\
-==================================================================\n\
-";
-
-const char kPrintDrive[] = "\nDrive: %u\n";
-const char kPrintDriveInfo[] = " %-15u %-15u ";
-const char kPrintNTFSInfo[] = "%-15u %-15u";
-
-const char kPrintHelp[] = "\
-Recovers an NTFS partition with a corrupted MFT. \n\
- \n\
-Usage: scrounge drive start end cluster mft [outdir] \n\
- \n\
- drive: Physical drive number. \n\
- start: First sector of partition. \n\
- end: Last sector of partition. \n\
- cluster: Cluster size for the partition (in sectors). \n\
- mft: Offset from beginning of partition to MFT (in sectors). \n\
- outdir: Output directory (optional). \n\
- \n\
-";
-
-
-// ----------------------------------------------------------------------
-// Info functions
-
-int PrintNTFSInfo(HANDLE hDrive, uint64 tblSector)
-{
- byte sector[kSectorSize];
-
- uint64 pos = SECTOR_TO_BYTES(tblSector);
- LONG lHigh = HIGHDWORD(pos);
- if(SetFilePointer(hDrive, LOWDWORD(pos), &lHigh, FILE_BEGIN) == -1
- && GetLastError() != NO_ERROR)
- return 1;
-
- DWORD dwRead = 0;
- if(!ReadFile(hDrive, sector, kSectorSize, &dwRead, NULL))
- return 1;
-
- NTFS_BootSector* pBoot = (NTFS_BootSector*)sector;
- if(!memcmp(pBoot->sysId, kNTFS_SysId, sizeof(pBoot->sysId)))
- printf(kPrintNTFSInfo, pBoot->secPerClus, pBoot->offMFT * pBoot->secPerClus);
-
- wprintf(L"\n");
- return 0;
-}
-
-
-int PrintPartitionInfo(HANDLE hDrive, uint64 tblSector)
-{
- ASSERT(sizeof(Drive_MBR) == kSectorSize);
- Drive_MBR mbr;
-
- uint64 pos = SECTOR_TO_BYTES(tblSector);
- LONG lHigh = HIGHDWORD(pos);
- if(SetFilePointer(hDrive, LOWDWORD(pos), &lHigh, FILE_BEGIN) == -1
- && GetLastError() != NO_ERROR)
- return 1;
-
- DWORD dwRead = 0;
- if(!ReadFile(hDrive, &mbr, sizeof(Drive_MBR), &dwRead, NULL))
- return 1;
-
- if(mbr.sig == kMBR_Sig)
+ /* Loop through sectors */
+ for(sec = pi->first; sec < pi->end; sec++)
{
- for(int i = 0; i < 4; i++)
- {
- if(mbr.partitions[i].system == kPartition_Extended ||
- mbr.partitions[i].system == kPartition_ExtendedLBA)
- {
- PrintPartitionInfo(hDrive, tblSector + mbr.partitions[i].startsec);
- }
- else if(!mbr.partitions[i].system == kPartition_Invalid)
- {
- printf(kPrintDriveInfo, (uint32)tblSector + mbr.partitions[i].startsec, (uint32)tblSector + mbr.partitions[i].endsec);
- PrintNTFSInfo(hDrive, tblSector + (uint64)mbr.partitions[i].startsec);
- }
- }
- }
-
- return 0;
-}
+ if(checkLocationLock(&locks, sec))
+ continue;
-const WCHAR kDriveName[] = L"\\\\.\\PhysicalDrive%d";
+ /* Read the record */
+ pos = SECTOR_TO_BYTES(sec);
+ if(_lseeki64(pi->device, pos, SEEK_SET) == -1)
+ errx(1, "can't seek device to sector");
-int PrintData()
-{
- printf(kPrintHeader);
- printf(kPrintData);
+ sz = read(pi->device, buffSec, kSectorSize);
+ if(sz == -1 || sz != kSectorSize)
+ errx(1, "can't read drive sector");
- WCHAR driveName[MAX_PATH];
-
- // LIMIT: 256 Drives
- for(int i = 0; i < 0x100; i++)
- {
- wsprintf(driveName, kDriveName, i);
-
- HANDLE hDrive = CreateFile(driveName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
- if(hDrive != INVALID_HANDLE_VALUE)
+ /* Check beginning of sector for the magic signature */
+ if(!memcmp(&magic, &buffSec, sizeof(magic)))
{
- printf(kPrintDrive, i);
-
- PrintPartitionInfo(hDrive, 0);
-
- CloseHandle(hDrive);
+ /* Process the record */
+ processMFTRecord(pi, sec, 0);
}
}
- return 2;
+ pi->locks = NULL;
}
-
-
-// ----------------------------------------------------------------------
-// Main Program
-
-int main(int argc, char* argv[])
-{
- int curArg = 1;
-
- if(argc < 2)
- return PrintData();
-
-
- // Check for flags
- if(*(argv[curArg]) == '-' || *(argv[curArg]) == '/' )
- {
- char* arg = argv[curArg];
- arg++;
-
- while(*arg != '\0')
- {
- switch(tolower(*arg))
- {
-
- // Help
- case 'h':
- printf(kPrintHeader);
- printf(kPrintHelp);
- return 2;
-
- default:
- printf("scrounge: invalid option '%c'\n", *arg);
- return PrintData();
- }
-
- arg++;
- }
-
- curArg++;
- }
-
- PartitionInfo* pInfo = CreatePartitionInfo();
- if(!pInfo)
- {
- printf("scrounge: Out of Memory.\n");
- return 1;
- }
-
- if(curArg + 5 > argc)
- {
- printf("scrounge: invalid option(s).\n");
- return 2;
- }
-
- // Next param should be the drive
- byte driveNum = atoi(argv[curArg++]);
-
- // Followed by the partition info
- pInfo->firstSector = atoi(argv[curArg++]);
- pInfo->lastSector = atoi(argv[curArg++]);
- pInfo->clusterSize = atoi(argv[curArg++]);
- pInfo->offMFT = atoi(argv[curArg++]);
-
- if(pInfo->firstSector == 0 ||
- pInfo->lastSector == 0 ||
- pInfo->clusterSize == 0 ||
- pInfo->offMFT == 0)
- {
- printf("scrounge: invalid option(s).\n");
- return 2;
- }
-
-// pInfo->clusterSize = 8;
-// pInfo->firstSector = 20482938/*128*/;
-// pInfo->lastSector = 80019765/*15358077*/;
-// pInfo->offMFT = 32;
-
- if(curArg <= argc)
- SetCurrentDirectoryA(argv[curArg++]);
-
- WCHAR driveName[MAX_PATH];
-
- wsprintf(driveName, kDriveName, driveNum);
-
- HANDLE hDrive = CreateFile(driveName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
- if(hDrive == INVALID_HANDLE_VALUE)
- {
- printf("scrounge: Can't open drive %d.\n", driveNum);
- return 2;
- }
-
- if(!ScroungeMFTRecords(pInfo, hDrive))
- {
- printf("scrounge: ");
- PrintLastError();
- fputc('\n', stdout);
- return 2;
- }
-
- FreePartitionInfo(pInfo);
-
- return 0;
-} \ No newline at end of file
diff --git a/src/scrounge.h b/src/scrounge.h
index b425db9..9baf720 100644
--- a/src/scrounge.h
+++ b/src/scrounge.h
@@ -1,38 +1,34 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
#ifndef __SCROUNGE_H__
#define __SCROUNGE_H__
-#define RET_ERROR(l) { ::SetLastError(l); bRet = TRUE; goto clean_up; }
-#define PASS_ERROR() {bRet = TRUE; goto clean_up; }
-#define RET_FATAL(l) { ::SetLastError(l); bRet = FALSE; goto clean_up; }
-#define PASS_FATAL() {bRet = FALSE; goto clean_up; }
+#include "drive.h"
-BOOL ProcessMFTRecord(PartitionInfo* pInfo, uint64 sector, NTFS_MFTMap* map, HANDLE hIn);
-BOOL ScroungeMFTRecords(PartitionInfo* pInfo, HANDLE hIn);
-BOOL ScroungeRawRecords(PartitionInfo* pInfo, HANDLE hIn);
-void PrintLastError();
+void scroungeSearch(partitioninfo* pi);
+void scroungeList();
+void scroungeUsingMFT(partitioninfo* pi);
+void scroungeUsingRaw(partitioninfo* pi);
+/* For compatibility */
+void setFileAttributes(wchar_t* filename, uint32 flags);
+void setFileTime(wchar_t* filename, uint64* created, uint64* accessed, uint64* modified);
-
-#endif //__SCROUNGE_H__ \ No newline at end of file
+#endif /* __SCROUNGE_H__ */
diff --git a/src/search.c b/src/search.c
new file mode 100644
index 0000000..4ab9823
--- /dev/null
+++ b/src/search.c
@@ -0,0 +1,32 @@
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+
+#include <stdio.h>
+#include "drive.h"
+
+void scroungeSearch(partitioninfo* pi)
+{
+ fprintf(stderr, "[Performing NTFS partition search...]");
+ errx(1, "search functionality not implemented yet.");
+
+ /* go through all sectors until we find an MFT record */
+ /* that isn't the MFT mirror */
+
+}
diff --git a/src/usuals.h b/src/usuals.h
index 8961592..0697956 100644
--- a/src/usuals.h
+++ b/src/usuals.h
@@ -1,29 +1,28 @@
-//
-// AUTHOR
-// N. Nielsen
-//
-// VERSION
-// 0.7
-//
-// LICENSE
-// This software is in the public domain.
-//
-// The software is provided "as is", without warranty of any kind,
-// express or implied, including but not limited to the warranties
-// of merchantability, fitness for a particular purpose, and
-// noninfringement. In no event shall the author(s) be liable for any
-// claim, damages, or other liability, whether in an action of
-// contract, tort, or otherwise, arising from, out of, or in connection
-// with the software or the use or other dealings in the software.
-//
-// SUPPORT
-// Send bug reports to: <nielsen@memberwebs.com>
-//
-
-#ifndef __USUALS_H__20010822
-#define __USUALS_H__20010822
-
-#include <win32/debug.h>
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#ifndef __USUALS_H__
+#define __USUALS_H__
+
+#include "debug.h"
+#include "compat.h"
+#include <errno.h>
typedef unsigned __int64 uint64;
typedef unsigned long uint32;
@@ -38,8 +37,17 @@ typedef signed short int16;
#define NULL 0
#endif
+#define RETWARNBX(s) { ret = false; warnx(s); goto cleanup; }
+#define RETWARNB(s) { ret = false; warn(s); goto cleanup; }
+#define RETWARNX(s) { warnx(s); goto cleanup; }
+#define RETWARN(s) { warn(s); goto cleanup; }
+#define RETURN goto cleanup
#define HIGHDWORD(i64) (DWORD)((i64) >> 32)
#define LOWDWORD(i64) (DWORD)((i64) & 0xFFFFFFFF)
-#endif //__USUALS_H__20010822
+
+#define INTERSECTS(b1, e1, b2, e2) \
+ ((b1) < (e2) && (e1) > (b2))
+
+#endif /* __USUALS_H__ */
diff --git a/src/win32.c b/src/win32.c
new file mode 100644
index 0000000..0726fad
--- /dev/null
+++ b/src/win32.c
@@ -0,0 +1,78 @@
+/*
+ * AUTHOR
+ * N. Nielsen
+ *
+ * LICENSE
+ * This software is in the public domain.
+ *
+ * The software is provided "as is", without warranty of any kind,
+ * express or implied, including but not limited to the warranties
+ * of merchantability, fitness for a particular purpose, and
+ * noninfringement. In no event shall the author(s) be liable for any
+ * claim, damages, or other liability, whether in an action of
+ * contract, tort, or otherwise, arising from, out of, or in connection
+ * with the software or the use or other dealings in the software.
+ *
+ * SUPPORT
+ * Send bug reports to: <nielsen@memberwebs.com>
+ */
+
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+
+#include "usuals.h"
+#include "ntfs.h"
+
+const char kDriveName[] = "\\\\.\\PhysicalDrive%d";
+
+#define ntfs_makefiletime(i64, ft) \
+ ((ft).dwLowDateTime = LOWDWORD(i64), (ft).dwHighDateTime = HIGHDWORD(i64))
+
+void makeDriveName(char* driveName, int i)
+{
+ wsprintf(driveName, kDriveName, i);
+}
+
+void setFileTime(wchar_t* filename, uint64* created,
+ uint64* accessed, uint64* modified)
+{
+ FILETIME ftcr;
+ FILETIME ftac;
+ FILETIME ftmd;
+ HANDLE file;
+
+ ntfs_makefiletime(*created, ftcr);
+ ntfs_makefiletime(*accessed, ftac);
+ ntfs_makefiletime(*modified, ftmd);
+
+ /* Write to the File */
+ file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if(file == INVALID_HANDLE_VALUE)
+ {
+ warnx("couldn't set file time: %S", filename);
+ return;
+ }
+
+ if(!SetFileTime(file, &ftcr, &ftac, &ftmd))
+ warnx("couldn't set file time: %S", filename);
+
+ CloseHandle(file);
+}
+
+void setFileAttributes(wchar_t* filename, uint32 flags)
+{
+ DWORD attributes;
+
+ /* Attributes */
+ if(flags & kNTFS_FileReadOnly)
+ attributes |= FILE_ATTRIBUTE_READONLY;
+ if(flags & kNTFS_FileHidden)
+ attributes |= FILE_ATTRIBUTE_HIDDEN;
+ if(flags & kNTFS_FileArchive)
+ attributes |= FILE_ATTRIBUTE_ARCHIVE;
+ if(flags & kNTFS_FileSystem)
+ attributes |= FILE_ATTRIBUTE_SYSTEM;
+
+ if(!SetFileAttributesW(filename, attributes))
+ warnx("couldn't set file attributes: %S", filename);
+}
diff --git a/win32/win32.dsp b/win32/win32.dsp
index dbb5213..91efad7 100644
--- a/win32/win32.dsp
+++ b/win32/win32.dsp
@@ -1,24 +1,24 @@
-# Microsoft Developer Studio Project File - Name="Scrounge" - Package Owner=<4>
+# Microsoft Developer Studio Project File - Name="win32" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
-CFG=Scrounge - Win32 Debug
+CFG=win32 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
-!MESSAGE NMAKE /f "Scrounge.mak".
+!MESSAGE NMAKE /f "win32.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
-!MESSAGE NMAKE /f "Scrounge.mak" CFG="Scrounge - Win32 Debug"
+!MESSAGE NMAKE /f "win32.mak" CFG="win32 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
-!MESSAGE "Scrounge - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "Scrounge - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "win32 - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "win32 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
@@ -28,7 +28,7 @@ CFG=Scrounge - Win32 Debug
CPP=cl.exe
RSC=rc.exe
-!IF "$(CFG)" == "Scrounge - Win32 Release"
+!IF "$(CFG)" == "win32 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
@@ -41,8 +41,8 @@ RSC=rc.exe
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /D "UNICODE" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@@ -50,10 +50,10 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /opt:nowin98
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/scrounge-ntfs.exe" /opt:nowin98
# SUBTRACT LINK32 /pdb:none
-!ELSEIF "$(CFG)" == "Scrounge - Win32 Debug"
+!ELSEIF "$(CFG)" == "win32 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
@@ -66,8 +66,8 @@ LINK32=link.exe
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UNICODE" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
@@ -75,44 +75,52 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/scrounge-ntfs.exe" /pdbtype:sept
!ENDIF
# Begin Target
-# Name "Scrounge - Win32 Release"
-# Name "Scrounge - Win32 Debug"
+# Name "win32 - Win32 Release"
+# Name "win32 - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
-SOURCE=.\drive.cpp
-# SUBTRACT CPP /YX /Yc /Yu
+SOURCE=..\src\compat.c
# End Source File
# Begin Source File
-SOURCE=.\memref.cpp
-# SUBTRACT CPP /YX /Yc /Yu
+SOURCE=..\src\list.c
# End Source File
# Begin Source File
-SOURCE=.\ntfs.cpp
-# SUBTRACT CPP /YX /Yc /Yu
+SOURCE=..\src\main.c
# End Source File
# Begin Source File
-SOURCE=.\ntfsx.cpp
+SOURCE=..\src\misc.c
# End Source File
# Begin Source File
-SOURCE=.\Scrounge.cpp
+SOURCE=..\src\ntfs.c
# End Source File
# Begin Source File
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"stdafx.h"
+SOURCE=..\src\ntfsx.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\scrounge.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\search.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\win32.c
# End Source File
# End Group
# Begin Group "Header Files"
@@ -120,23 +128,39 @@ SOURCE=.\StdAfx.cpp
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
-SOURCE=.\drive.h
+SOURCE=..\src\compat.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\debug.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\drive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\locks.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\memref.h
# End Source File
# Begin Source File
-SOURCE=.\ntfs.h
+SOURCE=..\src\ntfs.h
# End Source File
# Begin Source File
-SOURCE=.\ntfsx.h
+SOURCE=..\src\ntfsx.h
# End Source File
# Begin Source File
-SOURCE=.\scrounge.h
+SOURCE=..\src\scrounge.h
# End Source File
# Begin Source File
-SOURCE=.\StdAfx.h
+SOURCE=..\src\usuals.h
# End Source File
# End Group
# Begin Group "Resource Files"
diff --git a/win32/win32.dsw b/win32/win32.dsw
index b27fd20..5c8ab56 100644
--- a/win32/win32.dsw
+++ b/win32/win32.dsw
@@ -3,7 +3,7 @@ Microsoft Developer Studio Workspace File, Format Version 6.00
###############################################################################
-Project: "Scrounge"=.\Scrounge.dsp - Package Owner=<4>
+Project: "win32"=".\win32.dsp" - Package Owner=<4>
Package=<5>
{{{