From 94ba99e2ccdfaf862af6ce039ae447eb244c9283 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sat, 3 Apr 2004 05:42:49 +0000 Subject: Prep for unix porting --- .cvsignore | 4 +- src/compat.c | 241 +++++++++++++++++++++------------------------------------ src/compat.h | 204 ++++++++++++++++++++++++++++++++---------------- src/drive.h | 6 +- src/list.c | 20 +++-- src/main.c | 60 ++++++++++++-- src/memref.h | 8 +- src/misc.c | 75 +++++++++--------- src/ntfs.h | 4 + src/ntfsx.c | 2 +- src/posix.c | 89 +++++++++++++++++++++ src/scrounge.c | 88 +++++++++++++-------- src/scrounge.h | 5 +- src/unicode.c | 141 +++++++++++++++++++++++++++++++++ src/win32.c | 10 +-- 15 files changed, 644 insertions(+), 313 deletions(-) create mode 100644 src/posix.c create mode 100644 src/unicode.c diff --git a/.cvsignore b/.cvsignore index a243ba0..c5c3c75 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,3 +1 @@ -Debug -Release -Trash \ No newline at end of file +trash \ No newline at end of file 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 #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 -#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 #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 @@ -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 #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 +#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, §or, 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: + */ + + +#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 + +#include +#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); } -- cgit v1.2.3