summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compat.c241
-rw-r--r--src/compat.h204
-rw-r--r--src/drive.h6
-rw-r--r--src/list.c20
-rw-r--r--src/main.c60
-rw-r--r--src/memref.h8
-rw-r--r--src/misc.c75
-rw-r--r--src/ntfs.h4
-rw-r--r--src/ntfsx.c2
-rw-r--r--src/posix.c89
-rw-r--r--src/scrounge.c88
-rw-r--r--src/scrounge.h5
-rw-r--r--src/unicode.c141
-rw-r--r--src/win32.c10
14 files changed, 643 insertions, 310 deletions
diff --git a/src/compat.c b/src/compat.c
index 5ee1c0e..b183a99 100644
--- a/src/compat.c
+++ b/src/compat.c
@@ -27,139 +27,6 @@
#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
@@ -424,24 +291,6 @@ void vwarnx(const char *fmt, va_list ap)
#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)
@@ -455,3 +304,93 @@ void* reallocf(void* ptr, size_t size)
}
#endif
+
+#ifndef HAVE_ITOW
+wchar_t* itow(int val, wchar_t* out, int radix)
+{
+ int mod;
+ wchar_t temp;
+ wchar_t* end = out;
+ wchar_t* beg = out;
+
+ if(val != 0)
+ {
+ /* If negative and decimal*/
+ if(radix == 10 && val < 0)
+ *beg++ = L'-';
+
+ /* Convert in reverse order */
+ while(val != 0)
+ {
+ mod = val % radix;
+ val = val / radix;
+
+ *end++ = (mod < 10) ? L'0' + mod : L'a' + mod - 10;
+ }
+
+ *end-- = 0;
+
+ /* Reverse output string */
+ while(end > beg)
+ {
+ temp = *end;
+ *end = *beg;
+ *beg = temp;
+ ++beg;
+ --end;
+ }
+ }
+ else
+ {
+ beg[0] = L'0';
+ beg[1] = 0;
+ }
+
+ return out;
+}
+#endif
+
+#ifndef HAVE_ITOA
+wchar_t* itow(int val, wchar_t* out, int radix)
+{
+ int mod;
+ wchar_t temp;
+ wchar_t* end = out;
+ wchar_t* beg = out;
+
+ if(val != 0)
+ {
+ /* If negative and decimal*/
+ if(radix == 10 && val < 0)
+ *beg++ = L'-';
+
+ /* Convert in reverse order */
+ while(val != 0)
+ {
+ mod = val % radix;
+ val = val / radix;
+
+ *end++ = (mod < 10) ? L'0' + mod : L'a' + mod - 10;
+ }
+
+ *end-- = 0;
+
+ /* Reverse output string */
+ while(end > beg)
+ {
+ temp = *end;
+ *end = *beg;
+ *beg = temp;
+ ++beg;
+ --end;
+ }
+ }
+ else
+ {
+ beg[0] = L'0';
+ beg[1] = 0;
+ }
+
+ return out;
+}
+#endif \ No newline at end of file
diff --git a/src/compat.h b/src/compat.h
index cc3b73e..373d359 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -43,16 +43,6 @@
#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>
@@ -73,44 +63,11 @@
#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
+#ifndef HAVE_BOOL
typedef unsigned char bool;
#define false 0x00
#define true 0x01
@@ -126,30 +83,6 @@ 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
@@ -182,4 +115,139 @@ void vwarnx(const char *fmt, va_list ap);
void* reallocf(void* ptr, size_t size);
#endif
+/* Some number conversion stuff */
+
+#ifndef HAVE_ITOW
+ #ifdef _WIN32
+ #define itow _itow
+ #define HAVE_ITOW 1
+ #else
+ wchar_t itow(int v, wchar_t* s, int r);
+ #endif
+#endif
+
+#ifndef HAVE_ITOA
+ #ifdef _WIN32
+ #define itoa _itoa
+ #define HAVE_ITOA 1
+ #else
+ char itoa(int v, char* s, int r);
+ #endif
+#endif
+
+
+/*
+ * Depending on the OS we use different width characters
+ * for file names and file access. Before enabling wide
+ * file access for an OS the printf needs to be able to
+ * handle wide chars (ie: %S) and there should be wide
+ * char file access functions
+ */
+
+#ifdef _WIN32
+ /* On windows we use UCS2 */
+ typedef wchar_t fchar_t;
+ #define FC_WIDE 1
+ #define FC_PRINTF "%S"
+#else
+ /* Everywhere else we use UTF-8 */
+ typedef char fchar_t;
+ #undef FC_WIDE
+ #define FC_PRINTF "%s"
#endif
+
+#ifdef FC_WIDE
+
+ /* An OS that handles wide char file access */
+
+ #ifdef HAVE_WOPEN
+ #define fc_open wopen
+ #else
+ #ifdef _WIN32
+ #define fc_open _wopen
+ #else
+ #error Set for wide file access, but no wide open
+ #endif
+ #endif
+
+ #ifdef HAVE_WCHDIR
+ #define fc_chdir wchdir
+ #else
+ #ifdef _WIN32
+ #define fc_chdir _wchdir
+ #else
+ #error Set for wide file access but no wide chdir
+ #endif
+ #endif
+
+ #ifdef HAVE_WMKDIR
+ #define fc_mkdir wmkdir
+ #else
+ #ifdef _WIN32
+ #define fc_mkdir _wmkdir
+ #else
+ #error Set for wide file access but no wide mkdir
+ #endif
+ #endif
+
+ #ifdef HAVE_WGETCWD
+ #define fc_getcwd wgetcwd
+ #else
+ #ifdef _WIN32
+ #define fc_getcwd _wgetcwd
+ #else
+ #error Set for wide file access but no wide getcwd
+ #endif
+ #endif
+
+ #define fcscpy wcscpy
+ #define fcscat wcscat
+ #define fcsncpy wcsncpy
+ #define fcslen wcslen
+ #define fcscmp wcscmp
+ #define itofc itow
+
+ #define FC_DOT L"."
+
+#else
+
+ /* OSs without wide char file access */
+
+ #define fc_open open
+ #define fc_chdir chdir
+ #define fc_mkdir mkdir
+ #define fc_getcwd getcwd
+
+ #define fcscpy strcpy
+ #define fcscat strcat
+ #define fcslen strlen
+ #define fcscmp strcmp
+ #define itofc itoa
+
+ #define FC_DOT "."
+
+#endif
+
+
+
+/* 64 bit file handling stuff */
+
+#ifndef HAVE_LSEEK64
+ #ifdef _WIN32
+ #define lseek64 _lseeki64
+ #else
+ #ifdef HAVE_64BITOFFT
+ #define lseek64 lseek
+ #else
+ #error ERROR: Must have a working 64 bit seek function
+ #endif
+ #endif
+#endif
+
+#include <fnctl.h>
+#ifdef O_LARGEFILE
+ #define OPEN_LARGE_OPTS O_LARGEFILE
+#else
+ #define OPEN_LARGE_OPTS 0
+#endif
+
diff --git a/src/drive.h b/src/drive.h
index 4c52584..22e7d2d 100644
--- a/src/drive.h
+++ b/src/drive.h
@@ -83,7 +83,9 @@ drive_mbr;
#define SECTOR_TO_BYTES(sec) ((sec) * kSectorSize)
#define CLUSTER_SIZE(info) ((info).cluster * kSectorSize)
-/* driveName should be MAX_PATH chars long */
-void makeDriveName(char* driveName, int i);
+#ifdef _WIN32
+ /* driveName should be MAX_PATH chars long */
+ void makeDriveName(char* driveName, int i);
+#endif
#endif /* __DRIVE_H__ */
diff --git a/src/list.c b/src/list.c
index 28f2952..f93f3c0 100644
--- a/src/list.c
+++ b/src/list.c
@@ -33,6 +33,7 @@ const char kPrintData[] = "\
";
const char kPrintDrive[] = "\nDrive: %u\n";
+const char kPrintDrivePath[] = "\nDrive: %s\n";
const char kPrintDriveInfo[] = " %-15u %-15u ";
const char kPrintNTFSInfo[] = "%-15u %-15u";
@@ -45,8 +46,7 @@ int printNTFSInfo(int dd, uint64 tblSector)
pos = SECTOR_TO_BYTES(tblSector);
- /* PORT: Windows specific */
- if(_lseeki64(dd, pos, SEEK_SET) == -1)
+ if(lseek64(dd, pos, SEEK_SET) == -1)
err(1, "couldn't seek drive");
sz = read(dd, &sector, kSectorSize);
@@ -75,8 +75,7 @@ int printPartitionInfo(int dd, uint64 tblSector)
pos = SECTOR_TO_BYTES(tblSector);
- /* PORT: Windows specific */
- if(_lseeki64(dd, pos, SEEK_SET) == -1)
+ if(lseek64(dd, pos, SEEK_SET) == -1)
err(1, "couldn't seek drive");
sz = read(dd, &mbr, sizeof(drive_mbr));
@@ -120,7 +119,7 @@ void scroungeList()
{
makeDriveName(driveName, i);
- dd = open(driveName, _O_BINARY | _O_RDONLY);
+ dd = open(driveName, _O_BINARY | _O_RDONLY | OPEN_LARGE_OPTS);
if(dd != -1)
{
printf(kPrintDrive, i);
@@ -129,3 +128,14 @@ void scroungeList()
}
}
}
+
+void scroungeListDrive(char* drive)
+{
+ int dd = open(driveName, _O_BINARY | _O_RDONLY | OPEN_LARGE_OPTS;
+ if(dd == -1)
+ err(1, "couldn't open drive: %s", driveName);
+
+ printf(kPrintDrivePath, driveName);
+ printPartitionInfo(dd, 0);
+ close(dd);
+}
diff --git a/src/main.c b/src/main.c
index 39ff0c9..5cde040 100644
--- a/src/main.c
+++ b/src/main.c
@@ -27,6 +27,8 @@
#include "scrounge.h"
#include "compat.h"
+#ifdef _WIN32
+
const char kPrintHelp[] = "\
usage: scrounge -l \n\
List all drive partition information. \n\
@@ -45,6 +47,28 @@ usage: scrounge [-d drive] [-m mftoffset] [-c clustersize] [-o outdir] start end
\n\
";
+#else /* Not WIN32 */
+
+const char kPrintHelp[] = "\
+usage: scrounge -l \n\
+ List all drive partition information. \n\
+ \n\
+usage: scrounge -s disk \n\
+ Search drive for NTFS partitions. \n\
+ \n\
+usage: scrounge [-m mftoffset] [-c clustersize] [-o outdir] disk start end \n\
+ Scrounge data from a partition \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\
+ disk The raw disk partitios (ie: /dev/hda) \n\
+ start First sector of partition \n\
+ end Last sector of partition \n\
+ \n\
+";
+
+#endif
+
#define MODE_SCROUNGE 1
#define MODE_LIST 2
#define MODE_SEARCH 3
@@ -58,16 +82,22 @@ int main(int argc, char* argv[])
int temp = 0;
int mode = 0;
int raw = 0;
- int drive = 0;
partitioninfo pi;
char driveName[MAX_PATH];
+#ifdef _WIN32
+ int drive = 0;
+#endif
memset(&pi, 0, sizeof(pi));
/* TODO: We need to be able to autodetect the cluster size */
pi.cluster = 8;
+#ifdef _WIN32
while((ch = getopt(argc, argv, "c:d:hlm:o:s")) != -1)
+#else
+ while((ch = getopt(argc, argv, "c:hlm:o:s")) != -1)
+#endif
{
switch(ch)
{
@@ -86,6 +116,7 @@ int main(int argc, char* argv[])
}
break;
+#ifdef _WIN32
/* drive number */
case 'd':
{
@@ -98,6 +129,7 @@ int main(int argc, char* argv[])
drive = temp;
}
break;
+#endif
/* help mode */
case 'h':
@@ -156,6 +188,21 @@ int main(int argc, char* argv[])
argc -= optind;
argv += optind;
+#ifdef _WIN32
+ /* Under windows we format the drive number */
+ makeDriveName(driveName, drive);
+
+#else
+ /* Now when not under Windows, it's the drive name */
+ if(argc < 1)
+ errx(2, "must specify drive name");
+
+ driveName = argv[0];
+ argv++;
+ argc--;
+#endif
+
+
if(mode == MODE_SCROUNGE || mode == 0)
{
/* Get the sectors */
@@ -178,11 +225,10 @@ int main(int argc, char* argv[])
pi.end = temp;
- makeDriveName(driveName, drive);
-
- pi.device = open(driveName, _O_BINARY | _O_RDONLY);
+ /* Open the device */
+ pi.device = open(driveName, _O_BINARY | _O_RDONLY | OPEN_LARGE_OPTS);
if(pi.device == -1)
- err(1, "couldn't open drive");
+ err(1, "couldn't open drive: %s", driveName);
/* Use mft type search */
if(pi.mft != 0)
@@ -205,7 +251,11 @@ int main(int argc, char* argv[])
/* List partition and drive info */
if(mode == MODE_LIST)
+#ifdef _WIN32
scroungeList();
+#else
+ scroungeListDrive(driveName);
+#endif
/* Search for NTFS partitions */
if(mode == MODE_SEARCH)
diff --git a/src/memref.h b/src/memref.h
index 1138b63..270b8e4 100644
--- a/src/memref.h
+++ b/src/memref.h
@@ -23,8 +23,8 @@
#ifdef _DEBUG
void* _refalloc_dbg(size_t sz);
-void* _refadd_dbg(void* pBuff);
-void _refrelease_dbg(void* pBuff);
+void* _refadd_dbg(void* buf);
+void _refrelease_dbg(void* buf);
#define refalloc _refalloc_dbg
#define refadd _refadd_dbg
@@ -33,8 +33,8 @@ void _refrelease_dbg(void* pBuff);
#else
void* _refalloc(size_t sz);
-void* _refadd(void* pBuff);
-void _refrelease(void* pBuff);
+void* _refadd(void* buf);
+void _refrelease(void* buf);
#define refalloc _refalloc
#define refadd _refadd
diff --git a/src/misc.c b/src/misc.c
index 4f48b1e..0bb65ac 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -42,12 +42,13 @@ void addLocationLock(drivelocks* locks, uint64 beg, uint64 end)
if(locks->_count <= locks->_current)
{
locks->_count += 0x400;
- locks->_locks = (struct drivelock*)realloc(locks->_locks, sizeof(struct drivelock) * locks->_count);
- }
+ locks->_locks = (struct drivelock*)reallocf(locks->_locks, sizeof(struct drivelock) * locks->_count);
+
+ if(!locks->_locks)
+ errx(1, "out of memory");
+ }
/* 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 */
@@ -114,80 +115,82 @@ const size_t kRefSig = 0x1F2F3F4F;
void* _refalloc_dbg(size_t sz)
{
/* Allocate extra counter value before memory */
- size_t* pMem = (size_t*)malloc(sz * sizeof(size_t) * 2);
+ size_t* mem = (size_t*)malloc(sz * sizeof(size_t) * 2);
- if(pMem)
+ if(mem)
{
- pMem[0] = kRefSig;
- pMem[1] = 1;
- return pMem + 2;
+ mem[0] = kRefSig;
+ mem[1] = 1;
+ return mem + 2;
}
- return pMem;
+ return mem;
}
#endif
void* _refalloc(size_t sz)
{
/* Allocate extra counter value before memory */
- size_t* pMem = (size_t*)malloc(sz * sizeof(size_t) * 1);
+ size_t* mem = (size_t*)malloc(sz * sizeof(size_t) * 1);
- if(pMem)
+ if(mem)
{
- pMem[0] = 1;
- return pMem + 1;
+ mem[0] = 1;
+ return mem + 1;
}
- return pMem;
+ return mem;
}
#ifdef _DEBUG
-void* _refadd_dbg(void* pBuff)
+void* _refadd_dbg(void* buf)
{
- if(pBuff)
+ if(buf)
{
/* Increment the counter value */
- size_t* pMem = (size_t*)pBuff - 2;
- assert(pMem[0] == kRefSig);
- pMem[1]++;
+ size_t* mem = (size_t*)buf - 2;
+ assert(mem[0] == kRefSig);
+ mem[1]++;
}
- return pBuff;
+ return buf;
}
#endif
-void* _refadd(void* pBuff)
+void* _refadd(void* buf)
{
- if(pBuff)
+ if(buf)
/* Increment the counter value */
- ((size_t*)pBuff)[-1]++;
+ ((size_t*)buf)[-1]++;
- return pBuff;
+ return buf;
}
#ifdef _DEBUG
-void _refrelease_dbg(void* pBuff)
+void _refrelease_dbg(void* buf)
{
- if(pBuff)
+ if(buf)
{
/* Decrement the counter value */
- size_t* pMem = (size_t*)pBuff - 2;
- assert(pMem[0] == kRefSig);
+ size_t* mem = (size_t*)buf - 2;
+ assert(mem[0] == kRefSig);
- if(!--pMem[1])
- free(pMem);
+ if(!--mem[1])
+ free(mem);
}
}
#endif
-void _refrelease(void* pBuff)
+void _refrelease(void* buf)
{
- if(pBuff)
+ if(buf)
{
/* Decrement the counter value */
- size_t* pMem = (size_t*)pBuff - 1;
+ size_t* mem = (size_t*)buf - 1;
- if(!--pMem[0])
- free(pMem);
+ if(!--mem[0])
+ free(mem);
}
}
+
+
diff --git a/src/ntfs.h b/src/ntfs.h
index 0e5449b..e5eb1ec 100644
--- a/src/ntfs.h
+++ b/src/ntfs.h
@@ -191,4 +191,8 @@ byte* ntfs_getattributedata(ntfs_attribresident* attrib, byte* end);
bool ntfs_isbetternamespace(byte n1, byte n2);
bool ntfs_dofixups(byte* cluster, uint32 size);
+/* TODO: Move these declarations elsewhere */
+char* unicode_transcode16to8(const wchar_t* src, size_t len);
+wchar_t* unicode_transcode8to16(const char* src, const wchar_t* out, size_t len);
+
#endif /* __NTFS_H__ */
diff --git a/src/ntfsx.c b/src/ntfsx.c
index 8910f89..a3209e1 100644
--- a/src/ntfsx.c
+++ b/src/ntfsx.c
@@ -420,7 +420,7 @@ bool ntfsx_mftmap_load(ntfsx_mftmap* map, ntfsx_record* record, int dd)
if(map->_count >= allocated)
{
allocated += 16;
- map->_blocks = (struct _ntfsx_mftmap_block*)realloc(map->_blocks,
+ map->_blocks = (struct _ntfsx_mftmap_block*)reallocf(map->_blocks,
allocated * sizeof(struct _ntfsx_mftmap_block));
if(!(map->_blocks))
errx(1, "out of memory");
diff --git a/src/posix.c b/src/posix.c
new file mode 100644
index 0000000..0586715
--- /dev/null
+++ b/src/posix.c
@@ -0,0 +1,89 @@
+/*
+ * 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"
+
+/* NOTE: This file assumes that FC_WIDE is off */
+
+/* The NTFS file time is a a 64-bit value representing the
+ number of 100-nanosecond intervals since January 1, 1601 */
+
+/* The unix epoch in NTFS ft */
+#define UNIX_EPOCH 116444736000000000LL
+
+void ntfs_maketvs(uint64* ft, struct timeval* tv)
+{
+ /* Anything before the unix epoch is stupid */
+ if(*ft < UNIX_EPOCH)
+ {
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
+ }
+
+ /* Anything later than we can represent is a bummer */
+ else if(sizeof(tv->tv_sec) == 32)
+ {
+ tv->tv_sec = 0x7FFFFFFF;
+ tv->tv_usec = 0x7FFFFFFF;
+ }
+
+ /* Now convert the valid range of dates */
+ else
+ {
+ uint mod = (*ft % 1000000000);
+ tv->tv_sec = ((*ft - mod) / 1000000000);
+ tv->tv_usec = mod / 1000;
+ }
+};
+
+void setFileTime(fchar_t* filename, uint64* created,
+ uint64* accessed, uint64* modified)
+{
+ int r;
+ struct timeval tvs[2];
+ char* encoded;
+
+ ntfs_maketvs(accessed, tvs);
+ ntfs_maketvs(modified, tvs + 1);
+ if(utimes(filename, tvs) == -1)
+ warn("couldn't set file times on: %s", encoded);
+}
+
+void setFileAttributes(fchar_t* filename, uint32 flags)
+{
+ char* encoded;
+ struct stat st;
+
+ if(flags & kNTFS_FileReadOnly)
+ {
+ if(stat(filename, &st) == -1)
+ {
+ warn("couldn't read file status for: " FC_PRINTF, encoded);
+ }
+ else
+ {
+ if(chmod(filename, st.st_mode & ~(S_IWUSR | S_IWGRP | S_IOTH)) == -1)
+ warn("couldn't set file attributes for: " FC_PRINTF, encoded);
+ }
+ }
+}
+
+
diff --git a/src/scrounge.c b/src/scrounge.c
index f4436de..66297a8 100644
--- a/src/scrounge.c
+++ b/src/scrounge.c
@@ -30,7 +30,7 @@
typedef struct _filebasics
{
- wchar_t filename[MAX_PATH + 1];
+ fchar_t filename[MAX_PATH + 1];
uint64 created;
uint64 modified;
uint64 accessed;
@@ -48,6 +48,11 @@ void processRecordFileBasics(partitioninfo* pi, ntfsx_record* record, filebasics
byte* resident = NULL;
ntfs_attribfilename* filename;
byte nameSpace;
+ wchar_t* name;
+ size_t len;
+#ifndef FC_WIDE
+ char* temp;
+#endif
ASSERT(record);
memset(basics, 0, sizeof(filebasics));
@@ -82,15 +87,36 @@ void processRecordFileBasics(partitioninfo* pi, ntfsx_record* record, filebasics
basics->accessed = filename->timeRead;
/* File Name */
- wcsncpy(basics->filename, (wchar_t*)(((byte*)filename) + sizeof(ntfs_attribfilename)), filename->cFileName);
- basics->filename[filename->cFileName] = 0;
+ name = (wchar_t*)(((byte*)filename) + sizeof(ntfs_attribfilename));
+ len = filename->cFileName;
+ if(len > MAX_PATH)
+ len = MAX_PATH;
+
+#ifdef FC_WIDE
+ wcsncpy(basics->filename, name, len);
+#else
+ temp = unicode_transcode16to8(basics->filename, len);
+ if(!temp)
+ errx(1, "out of memory");
+
+ len = strlen(temp);
+ if(len > MAX_PATH)
+ len = MAX_PATH;
+
+ strncpy(basics->filename, temp, len);
+#endif
+
+ basics->filename[len] = 0;
+
/* Attributes */
basics->flags = filename->flags;
+
/* Parent Directory */
basics->parent = filename->refParent & 0xFFFFFFFFFFFF;
+
/* Namespace */
nameSpace = filename->nameSpace;
}
@@ -122,7 +148,7 @@ void processMFTRecord(partitioninfo* pi, uint64 sector, int level)
uint64 fileSize;
uint32 i;
uint32 num;
- wchar_t filename2[MAX_PATH + 1];
+ fchar_t filename2[MAX_PATH + 1];
ntfs_attribheader* attrhead;
ntfs_attribnonresident* nonres;
@@ -151,7 +177,7 @@ void processMFTRecord(partitioninfo* pi, uint64 sector, int level)
}
/* If it's the root folder then return */
- if(!wcscmp(basics.filename, L"."))
+ if(!fcscmp(basics.filename, FC_DOT))
RETURN;
/* Process parent folders if available */
@@ -163,30 +189,28 @@ void processMFTRecord(partitioninfo* pi, uint64 sector, int level)
parentSector = ntfsx_mftmap_sectorforindex(pi->mftmap, basics.parent);
if(parentSector == kInvalidSector)
- warnx("invalid parent directory for file: %S", basics.filename);
+ warnx("invalid parent directory for file: " FC_PRINTF, basics.filename);
else
processMFTRecord(pi, parentSector, level + 1);
}
}
- printf(level == 0 ? "\\%S\n" : "\\%S", basics.filename);
+ printf(level == 0 ? "\\" FC_PRINTF "\n" : "\\" FC_PRINTF, basics.filename);
/* Directory handling: */
if(header->flags & kNTFS_RecFlagDir)
{
/* Try to change to the directory */
- /* PORT: Wide character file functions */
- if(_wchdir(basics.filename) == -1)
+ if(wchdir(basics.filename) == -1)
{
- /* PORT: Wide character file functions */
- if(_wmkdir(basics.filename) == -1)
+ if(wmkdir(basics.filename) == -1)
{
- warnx("couldn't create directory '%S' putting files in parent directory", basics.filename);
+ warnx("couldn't create directory '" FC_PRINTF "' putting files in parent directory", basics.filename);
}
else
{
setFileAttributes(basics.filename, basics.flags);
- _wchdir(basics.filename);
+ wchdir(basics.filename);
}
}
@@ -195,32 +219,31 @@ void processMFTRecord(partitioninfo* pi, uint64 sector, int level)
/* Normal file handling: */
- /* PORT: Wide character file functions */
- outfile = _wopen(basics.filename, _O_BINARY | _O_CREAT | _O_EXCL | _O_WRONLY);
+ outfile = wopen(basics.filename, _O_BINARY | _O_CREAT | _O_EXCL | _O_WRONLY);
- wcsncpy(filename2, basics.filename, MAX_PATH);
+ fcsncpy(filename2, basics.filename, MAX_PATH);
filename2[MAX_PATH] = 0;
while(outfile == -1 && errno == EEXIST && rename < 0x1000)
{
- if(wcslen(basics.filename) + 7 >= MAX_PATH)
+ if(fcslen(basics.filename) + 7 >= MAX_PATH)
{
- warnx("file name too long on duplicate file: %S", basics.filename);
+ warnx("file name too long on duplicate file: " FC_PRINTF, basics.filename);
goto cleanup;
}
- wcscpy(basics.filename, filename2);
- wcscat(basics.filename, L".");
+ fcscpy(basics.filename, filename2);
+ fcscat(basics.filename, L".");
- _itow(rename, basics.filename + wcslen(basics.filename), 10);
+ itofc(rename, basics.filename + fcslen(basics.filename), 10);
rename++;
- outfile = _wopen(basics.filename, _O_BINARY | _O_CREAT | _O_EXCL | _O_WRONLY);
+ outfile = fc_open(basics.filename, _O_BINARY | _O_CREAT | _O_EXCL | _O_WRONLY);
}
if(outfile == -1)
{
- warnx("couldn't open output file: %S", basics.filename);
+ warnx("couldn't open output file: " FC_PRINTF, basics.filename);
goto cleanup;
}
@@ -282,7 +305,7 @@ void processMFTRecord(partitioninfo* pi, uint64 sector, int level)
num = (uint32)fileSize;
if(write(outfile, cluster.data, num) != (int32)num)
- err(1, "couldn't write to output file: %S", basics.filename);
+ err(1, "couldn't write to output file: " FC_PRINTF, basics.filename);
fileSize -= num;
}
@@ -308,7 +331,7 @@ void processMFTRecord(partitioninfo* pi, uint64 sector, int level)
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);
+ err(1, "couldn't write to output file: " FC_PRINTF, basics.filename);
fileSize -= num;
}
@@ -378,7 +401,7 @@ void scroungeMFT(partitioninfo* pi, ntfsx_mftmap* map)
processRecordFileBasics(pi, record, &basics);
- if(wcscmp(basics.filename, kNTFS_MFTName))
+ if(fcscmp(basics.filename, kNTFS_MFTName))
errx(2, "invalid mft. wrong record");
fprintf(stderr, "[Processing MFT...]\n");
@@ -398,7 +421,7 @@ void scroungeMFT(partitioninfo* pi, ntfsx_mftmap* map)
void scroungeUsingMFT(partitioninfo* pi)
{
uint64 numRecords = 0;
- char dir[MAX_PATH];
+ fchar_t dir[MAX_PATH];
ntfsx_mftmap map;
uint64 length;
uint64 sector;
@@ -407,7 +430,7 @@ void scroungeUsingMFT(partitioninfo* pi)
fprintf(stderr, "[Scrounging via MFT...]\n");
/* Save current directory away */
- getcwd(dir, MAX_PATH);
+ fc_getcwd(dir, MAX_PATH);
/* Get the MFT map ready */
memset(&map, 0, sizeof(map));
@@ -435,7 +458,7 @@ void scroungeUsingMFT(partitioninfo* pi)
processMFTRecord(pi, sector, 0);
/* Move to right output directory */
- chdir(dir);
+ fc_chdir(dir);
}
pi->mftmap = NULL;
@@ -444,7 +467,7 @@ void scroungeUsingMFT(partitioninfo* pi)
void scroungeUsingRaw(partitioninfo* pi)
{
byte buffSec[kSectorSize];
- char dir[_MAX_PATH + 1];
+ fchar_t dir[_MAX_PATH + 1];
uint64 sec;
drivelocks locks;
int64 pos;
@@ -454,7 +477,7 @@ void scroungeUsingRaw(partitioninfo* pi)
fprintf(stderr, "[Scrounging raw records...]\n");
/* Save current directory away */
- getcwd(dir, _MAX_PATH);
+ fc_getcwd(dir, _MAX_PATH);
/* Get the locks ready */
memset(&locks, 0, sizeof(locks));
@@ -481,6 +504,9 @@ void scroungeUsingRaw(partitioninfo* pi)
/* Process the record */
processMFTRecord(pi, sec, 0);
}
+
+ /* Move to right output directory */
+ fc_chdir(dir);
}
pi->locks = NULL;
diff --git a/src/scrounge.h b/src/scrounge.h
index 9baf720..b1425fd 100644
--- a/src/scrounge.h
+++ b/src/scrounge.h
@@ -24,11 +24,12 @@
void scroungeSearch(partitioninfo* pi);
void scroungeList();
+void scroungeListDrive(char* drive);
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);
+void setFileAttributes(fchar_t* filename, uint32 flags);
+void setFileTime(fchar_t* filename, uint64* created, uint64* accessed, uint64* modified);
#endif /* __SCROUNGE_H__ */
diff --git a/src/unicode.c b/src/unicode.c
new file mode 100644
index 0000000..a8fc612
--- /dev/null
+++ b/src/unicode.c
@@ -0,0 +1,141 @@
+
+#include <wchar.h>
+
+#include <wchar.h>
+#include "sablo.h"
+
+/*
+ * Transcode UCS2 to UTF8.
+ *
+ * Since the nature of the transformation is that the
+ * resulting length is unpredictable, this function
+ * allocates it's own memory.
+ */
+char* unicode_transcode16to8(const wchar_t* src, size_t len)
+{
+ char* ret = NULL;
+ size_t alloc = 0;
+ size_t pos = 0;
+ const wchar_t* c;
+ const wchar_t* e;
+
+ /* Allocate 1.25 times the length initially */
+ alloc = len + (len / 4) + 1;
+ ret = (char*)malloc(alloc * sizeof(char));
+ if(!ret) return NULL;
+
+ c = src;
+ e = c + len;
+
+ for( ; c < e; c++)
+ {
+ /* Make sure we have enough memory */
+ if(pos + 4 >= alloc)
+ {
+ alloc += (len / 2) + 1;
+ if(!(ret = (char*)reallocf(ret, alloc * sizeof(char))))
+ return NULL;
+ }
+
+ /* Encode as one character */
+ if(*c <= 0x007F)
+ {
+ ret[pos++] = (char)*c;
+ }
+
+ /* Encode as two characters */
+ else if(*c <= 0x07FF)
+ {
+ ret[pos++] = (char)(192 | (*c >> 6));
+ ret[pos++] = (char)(128 | (*c & 63));
+ }
+
+ /* Encode as three characters */
+ else
+ {
+ ret[pos++] = (char)(224 | (*c >> 12));
+ ret[pos++] = (char)(128 | ((*c >> 6) & 63));
+ ret[pos++] = (char)(128 | (*c & 63));
+ }
+ }
+
+ ret[pos] = NULL;
+ return ret;
+}
+
+/*
+ * Transcode UTF-8 to UCS2
+ *
+ * Since a semi predictable length of the resulting data is
+ * known, the caller should allocate the memory for this conversion.
+ */
+wchar_t* unicode_transcode8to16(const char* src, const wchar_t* out, size_t len)
+{
+ /* Note: out should always be at least as long as src in chars */
+
+ size_t pos = 0;
+ const char* c;
+ const char* e;
+
+ c = src;
+ e = c + len;
+
+ for( ; c < e; c++)
+ {
+ /* We never have to reallocate here. We will always
+ be using the same or less number of output characters
+ than input chars. That's just the nature of the encoding. */
+
+ /* First 4 bits set */
+ if((c + 3) < e &&
+ (c[0] & 0xF8) == 0xF0 &&
+ (c[1] & 0xC0) == 0x80 &&
+ (c[2] & 0xC0) == 0x80 &&
+ (c[3] & 0xC0) == 0x80)
+ {
+ out[pos++] = (wchar_t)(((wchar_t)c[0] & 7) << 18 |
+ ((wchar_t)c[1] & 63) << 12 |
+ ((wchar_t)c[2] & 63) << 6 |
+ ((wchar_t)c[3] & 63));
+ c += 3;
+ }
+
+ /* First 3 bits set */
+ else if((c + 2) < e &&
+ (c[0] & 0xF0) == 0xE0 &&
+ (c[1] & 0xC0) == 0x80 &&
+ (c[2] & 0xC0) == 0x80)
+ {
+ out[pos++] = (wchar_t)(((wchar_t)c[0] & 15) << 12 |
+ ((wchar_t)c[1] & 63) << 6 |
+ ((wchar_t)c[2] & 63));
+ c += 2;
+ }
+
+ /* First 2 bits set */
+ else if((c + 1) < e &&
+ (c[0] & 0xE0) == 0xC0 &&
+ (c[1] & 0xC0) == 0x80)
+ {
+ out[pos++] = (wchar_t)(((wchar_t)c[0] & 31) << 6 |
+ ((wchar_t)c[1] & 63));
+ c += 1;
+ }
+
+ /* First bit set */
+ else if(!(c[0] & 0x80))
+ {
+ out[pos++] = (wchar_t)c[0];
+ }
+
+ /* Invalid encoding */
+ else
+ {
+ out[pos++] = L'?';
+ }
+ }
+
+ out[pos] = NULL;
+ return out;
+}
+
diff --git a/src/win32.c b/src/win32.c
index 0726fad..3cb5b25 100644
--- a/src/win32.c
+++ b/src/win32.c
@@ -33,7 +33,7 @@ void makeDriveName(char* driveName, int i)
wsprintf(driveName, kDriveName, i);
}
-void setFileTime(wchar_t* filename, uint64* created,
+void setFileTime(fchar_t* filename, uint64* created,
uint64* accessed, uint64* modified)
{
FILETIME ftcr;
@@ -49,17 +49,17 @@ void setFileTime(wchar_t* filename, uint64* created,
file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(file == INVALID_HANDLE_VALUE)
{
- warnx("couldn't set file time: %S", filename);
+ warnx("couldn't set file time: " FC_PRINTF, filename);
return;
}
if(!SetFileTime(file, &ftcr, &ftac, &ftmd))
- warnx("couldn't set file time: %S", filename);
+ warnx("couldn't set file time: " FC_PRINTF, filename);
CloseHandle(file);
}
-void setFileAttributes(wchar_t* filename, uint32 flags)
+void setFileAttributes(fchar_t* filename, uint32 flags)
{
DWORD attributes;
@@ -74,5 +74,5 @@ void setFileAttributes(wchar_t* filename, uint32 flags)
attributes |= FILE_ATTRIBUTE_SYSTEM;
if(!SetFileAttributesW(filename, attributes))
- warnx("couldn't set file attributes: %S", filename);
+ warnx("couldn't set file attributes: " FC_PRINTF, filename);
}