From 3fec683bcc0f43b5820e910c3c58a5bc70d08c06 Mon Sep 17 00:00:00 2001 From: Christophe Grenier Date: Tue, 6 Nov 2007 16:40:46 +0100 Subject: [PATCH] Handle unicode filenames in display and when copying files from an NTFS partition Thanks to Kenneth, C H LEE for the first patch --- configure.ac | 157 ++++++++++++++++++++++++++++++++++++++++++------- src/common.c | 37 ++++++------ src/common.h | 3 +- src/fat_adv.c | 9 ++- src/ntfs_dir.c | 50 +++++++++++++++- src/ntfs_inc.h | 3 + src/ntfsp.c | 3 + src/parti386.c | 2 + src/photorec.c | 27 +++++---- src/testdisk.c | 29 ++++----- 10 files changed, 244 insertions(+), 76 deletions(-) diff --git a/configure.ac b/configure.ac index ec944ea3..1e8edc19 100644 --- a/configure.ac +++ b/configure.ac @@ -29,62 +29,101 @@ if test "x$nonopt" != "xNONE"; then fi # Command-line options. -AC_ARG_WITH([ext2fs], AS_HELP_STRING(--without-ext2fs,disabled use of the ext2fs library (default is NO)), +AC_ARG_WITH([ext2fs], + AS_HELP_STRING(--without-ext2fs,disabled use of the ext2fs library (default is NO)), [ use_ext2fs="n" ]) -AC_ARG_WITH(ext2fs-lib,[ --with-ext2fs-lib=DIR location of the ext2fs library], +AC_ARG_WITH(ext2fs-lib, + AS_HELP_STRING(--with-ext2fs-lib=DIR,location of the ext2fs library), [ ext2fs_lib_a="${withval}/libext2fs.a" LDFLAGS="${LDFLAGS} -L${withval}" ]) -AC_ARG_WITH(ext2fs-includes,[ --with-ext2fs-includes=DIR location of the ext2fs includes files], +AC_ARG_WITH(ext2fs-includes, + AS_HELP_STRING(--with-ext2fs-includes=DIR,location of the ext2fs includes files), [CPPFLAGS="${CPPFLAGS} -I${withval}"]) -AC_ARG_WITH([jpeg], AS_HELP_STRING(--without-jpeg,disabled use of the jpeg library (default is NO)), +AC_ARG_WITH([jpeg], + AS_HELP_STRING(--without-jpeg,disabled use of the jpeg library (default is NO)), [ use_jpeg="n" ]) -AC_ARG_WITH(jpegmmx-lib,[ --with-jpegmmx-lib=DIR location of the jpeg library], - [ jpegmmx_lib_a="${withval}/libjpeg-mmx.a" - LDFLAGS="${LDFLAGS} -L${withval}" ]) +#AC_ARG_WITH(jpegmmx-lib, +# AS_HELP_STRING(--with-jpegmmx-lib=DIR,location of the jpeg library), +# [ jpegmmx_lib_a="${withval}/libjpeg-mmx.a" +# LDFLAGS="${LDFLAGS} -L${withval}" ]) -AC_ARG_WITH(jpeg-lib,[ --with-jpeg-lib=DIR location of the jpeg library], +AC_ARG_WITH(jpeg-lib, + AS_HELP_STRING(--with-jpeg-lib=DIR,location of the jpeg library), [ jpeg_lib_a="${withval}/libjpeg.a" LDFLAGS="${LDFLAGS} -L${withval}" ]) -AC_ARG_WITH(jpeg-includes,[ --with-jpeg-includes=DIR location of the jpeg includes files], +AC_ARG_WITH(jpeg-includes, + AS_HELP_STRING(--with-jpeg-includes=DIR,location of the jpeg includes files), [CPPFLAGS="${CPPFLAGS} -I${withval}"]) -AC_ARG_WITH([ntfs], AS_HELP_STRING(--without-ntfs,disabled use of the ntfs library (default is NO)), +AC_ARG_WITH([ntfs], + AS_HELP_STRING(--without-ntfs,disabled use of the ntfs library (default is NO)), [ use_ntfs="n" ]) -AC_ARG_WITH(ntfs-lib,[ --with-ntfs-lib=DIR location of the ntfs library], +AC_ARG_WITH(ntfs-lib, + AS_HELP_STRING(--with-ntfs-lib=DIR,location of the ntfs library), [ ntfs_lib_a="${withval}/libntfs.a" LDFLAGS="${LDFLAGS} -L${withval}" ]) -AC_ARG_WITH(ntfs-includes,[ --with-ntfs-includes=DIR location of the ntfs includes files], +AC_ARG_WITH(ntfs-includes, + AS_HELP_STRING(--with-ntfs-includes=DIR,location of the ntfs includes files), [CPPFLAGS="${CPPFLAGS} -I${withval}"]) -AC_ARG_WITH(dal-lib,[ --with-dal-lib=DIR location of the dal library], +AC_ARG_WITH(dal-lib, + AS_HELP_STRING(--with-dal-lib=DIR,location of the dal library), [ LDFLAGS="${LDFLAGS} -L${withval}" ]) -AC_ARG_WITH([reiserfs], AS_HELP_STRING(--without-reiserfs,disabled use of the reiserfs library (default is NO)), +AC_ARG_WITH([reiserfs], + AS_HELP_STRING(--without-reiserfs,disabled use of the reiserfs library (default is NO)), [ use_reiserfs="n" ]) -AC_ARG_WITH(reiserfs-lib,[ --with-reiserfs-lib=DIR location of the reiserfs library], +AC_ARG_WITH(reiserfs-lib, + AS_HELP_STRING(--with-reiserfs-lib=DIR,location of the reiserfs library), [ reiserfs_lib_a="${withval}/libreiserfs.a" LDFLAGS="${LDFLAGS} -L${withval}" ]) -AC_ARG_WITH(reiserfs-includes,[ --with-reiserfs-includes=DIR location of the reiserfs includes files], +AC_ARG_WITH(reiserfs-includes, + AS_HELP_STRING(--with-reiserfs-includes=DIR,location of the reiserfs includes files), [CPPFLAGS="${CPPFLAGS} -I${withval}"]) -AC_ARG_WITH([ewf], AS_HELP_STRING(--without-ewf,disabled use of the ewf library (default is NO)), +AC_ARG_WITH([ewf], + AS_HELP_STRING(--without-ewf,disabled use of the ewf library (default is NO)), [ use_ewf="n" ]) -AC_ARG_WITH(ewf-lib,[ --with-ewf-lib=DIR location of the ewf library], +AC_ARG_WITH(ewf-lib, + AS_HELP_STRING(--with-ewf-lib=DIR,location of the ewf library), [ ewf_lib_a="${withval}/libewf.a" LDFLAGS="${LDFLAGS} -L${withval}" ]) -AC_ARG_WITH(ewf-includes,[ --with-ewf-includes=DIR location of the ewf includes files], +AC_ARG_WITH(ewf-includes, + AS_HELP_STRING(--with-ewf-includes=DIR,location of the ewf includes files), + [CPPFLAGS="${CPPFLAGS} -I${withval}"]) + +AC_ARG_WITH([iconv], + AS_HELP_STRING(--without-iconv,disabled use of the iconv library (default is NO)), + [ use_iconv="n" ]) + +AC_ARG_WITH(iconv-lib, + AS_HELP_STRING(--with-iconv-lib=DIR,location of the iconv library), + [ iconv_lib_a="${withval}/libiconv.a" + LDFLAGS="${LDFLAGS} -L${withval}" ]) + +AC_ARG_WITH(iconv-includes, + AS_HELP_STRING(--with-iconv-includes=DIR,location of the iconv includes files), + [CPPFLAGS="${CPPFLAGS} -I${withval}"]) + +AC_ARG_WITH(giconv-lib, + AS_HELP_STRING(--with-giconv-lib=DIR,location of the giconv library), + [ iconv_lib_a="${withval}/libgiconv.a" + LDFLAGS="${LDFLAGS} -L${withval}" ]) + +AC_ARG_WITH(giconv-includes, + AS_HELP_STRING(--with-giconv-includes=DIR,location of the giconv includes files), [CPPFLAGS="${CPPFLAGS} -I${withval}"]) use_icon=no @@ -139,7 +178,81 @@ AC_SYS_LARGEFILE AC_HEADER_STDC #AC_CHECK_HEADERS([sys/types.h sys/stat.h stdlib.h stdint.h unistd.h]) AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([byteswap.h curses.h cygwin/fs.h dal/file_dal.h dal/file.h dirent.h endian.h errno.h fcntl.h features.h glob.h libgen.h limits.h linux/fs.h linux/hdreg.h linux/types.h locale.h machine/endian.h ncurses.h ncurses/curses.h ncurses/ncurses.h ntfs/version.h openssl/md5.h openssl/opensslv.h setjmp.h signal.h stdarg.h sys/cygwin.h sys/disk.h sys/disklabel.h sys/dkio.h sys/endian.h sys/ioctl.h sys/param.h sys/select.h sys/time.h sys/utsname.h sys/vtoc.h time.h windef.h varargs.h utime.h zlib.h]) +AC_CHECK_HEADERS([byteswap.h curses.h cygwin/fs.h dal/file_dal.h dal/file.h dirent.h endian.h errno.h fcntl.h features.h giconv.h glob.h iconv.h libgen.h limits.h linux/fs.h linux/hdreg.h linux/types.h locale.h machine/endian.h ncurses.h ncurses/curses.h ncurses/ncurses.h ntfs/version.h openssl/md5.h openssl/opensslv.h setjmp.h signal.h stdarg.h sys/cygwin.h sys/disk.h sys/disklabel.h sys/dkio.h sys/endian.h sys/ioctl.h sys/param.h sys/select.h sys/time.h sys/utsname.h sys/vtoc.h time.h windef.h varargs.h utime.h zlib.h]) + +#-------------------------------------------------------------------- +# Check for iconv support (for Unicode conversion). +#-------------------------------------------------------------------- +# +# We need to find an iconv library that matches the installed iconv.h header +# (if any). It is important to check header/library compatibility. It's +# fairly common to have iconv support both in libc and from libiconv. In that +# case, a naive check that iconv() is in libc will succeed, but if we use +# libiconv's iconv.h, it will redefine iconv() to functions that exist +# only in libiconv, and we'll get link errors. +# +# First, check if there's a working iconv in libc (ie. if the test program +# compiles and links without any extra flags). +if test -z "${use_iconv}"; then +AC_MSG_CHECKING(iconv support) +AC_LINK_IFELSE([[#include +int main(int argc,char **argv) { iconv_open("foo","bar"); }]] +, + # libc has a working iconv. + AC_DEFINE(HAVE_ICONV,1, [Define if you have this function]) + AC_MSG_RESULT([[yes, in libc]]) + found_iconv=yes +, + found_iconv=no +) + +if test $found_iconv = no ; then + # libc doesn't have a working iconv. Try adding -liconv and any user + # supplied directory. + + old_LIBS="$LIBS" + if test "${iconv_lib_a}" = ""; then + LIBS="$LIBS -liconv" + else + LIBS="$LIBS ${iconv_lib_a}" + fi + AC_LINK_IFELSE([[#include + int main(int argc,char **argv) { iconv_open("foo","bar"); }]] + , + # -liconv works. + AC_DEFINE(HAVE_ICONV,1, [Define if you have this function]) + AC_MSG_RESULT([[yes, -liconv]]) + found_iconv=yes + , + found_iconv=no + LIBS="$old_LIBS" + ) +fi + +if test $found_iconv = no ; then + # -liconv didn't work. Try giconv.h and -lgiconv. + # BSDs install this lib as libgiconv. + old_LIBS="$LIBS" + if test "${giconv_lib_a}" = ""; then + LIBS="$LIBS -lgiconv" + else + LIBS="$LIBS ${giconv_lib_a}" + fi + AC_LINK_IFELSE([[#include + int main(int argc,char **argv) { iconv_open("foo","bar"); }]] + , + AC_DEFINE(HAVE_ICONV,1, [Define if you have this function]) + AC_DEFINE(HAVE_GICONV,1, [Define if you have this function]) + AC_MSG_RESULT([[yes, -lgiconv]]) + , + AC_MSG_RESULT([[no]]) + LIBS="$old_LIBS" + ) +fi +else + AC_MSG_WARN(Use of iconv function disabled) +fi + AC_CHECK_HEADERS(sys/mount.h,,, [[ @@ -212,9 +325,9 @@ AC_PROG_GCC_TRADITIONAL # Checks for libraries. if test -z "${use_ncurses}"; then - AC_SEARCH_LIBS(initscr, ncurses pdcurses curses, + AC_SEARCH_LIBS(initscr, ncursesw ncurses pdcurses curses, [ - AC_DEFINE([HAVE_NCURSES],1,[Define to 1 if you have one of the ncurses/pdcurses/curses library.]) + AC_DEFINE([HAVE_NCURSES],1,[Define to 1 if you have one of the ncursesw/ncurses/pdcurses/curses library.]) ],AC_MSG_ERROR(No ncurses library detected)) else AC_MSG_WARN(Use of ncurses library disabled) diff --git a/src/common.c b/src/common.c index 8024cf76..570f382b 100644 --- a/src/common.c +++ b/src/common.c @@ -219,24 +219,6 @@ static inline unsigned char convert_char(unsigned char car) /* 'y' */ if(car>=253) return 'y'; -#endif - return car; -} - -void filename_convert(char *dst, const char*src, const unsigned int n) -{ - unsigned int i; - for(i=0;i0 && (dst[i]==' '||dst[i]=='.')) - dst[i--]='\0'; -#endif -} - -static inline unsigned char filter_char(unsigned char car) -{ /* Chars allowed under msdos, a-z is stored as upercase by the OS itself */ if((car>='A' && car<='Z') || (car>='a' && car<='z')|| (car>='0' && car<='9')) return car; @@ -265,19 +247,34 @@ static inline unsigned char filter_char(unsigned char car) case '=': case '[': case ']': + case '/': /* without it, no subdirectory */ return car; } if(car>=224) return car; return '_'; +#endif + return car; } -void filename_cpy(char *dst, const char*src, const unsigned int n) +unsigned int filename_convert(char *dst, const char*src, const unsigned int n) { unsigned int i; for(i=0;i0 && (dst[i-1]==' '||dst[i-1]=='.')) + i--; + if(i==0 && (dst[i]==' '||dst[i]=='.')) + dst[i++]='_'; +#endif dst[i]='\0'; + return i; } void create_dir(const char *dir_name, const unsigned int is_dir_name) diff --git a/src/common.h b/src/common.h index 05969c06..d1455f0a 100644 --- a/src/common.h +++ b/src/common.h @@ -403,8 +403,7 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap); int strncasecmp(const char * s1, const char * s2, size_t len); #endif void create_dir(const char *dir_name, const unsigned int is_dir_name); -void filename_convert(char *dst, const char*src, const unsigned int n); -void filename_cpy(char *dst, const char*src, const unsigned int n); +unsigned int filename_convert(char *dst, const char*src, const unsigned int n); #ifdef DJGPP #define TESTDISK_OS "Dos version" diff --git a/src/fat_adv.c b/src/fat_adv.c index 12064fa0..8a2e1632 100644 --- a/src/fat_adv.c +++ b/src/fat_adv.c @@ -1918,7 +1918,7 @@ static int find_cluster_size_aux(const sector_cluster_t *sector_cluster, const u unsigned int nbr_sol=0; if(nbr_sector_cluster<2) return 0; - cluster_offset=MALLOC(nbr_sector_cluster*nbr_sector_cluster*sizeof(cluster_offset_t)); + cluster_offset=(cluster_offset_t *)MALLOC(nbr_sector_cluster*nbr_sector_cluster*sizeof(cluster_offset_t)); log_info("find_cluster_size_aux\n"); for(i=0;i0) { - log_verbose("cluster_size=%u offset=%lu nbr=%u ",cluster_offset[i].cluster_size,cluster_offset[i].offset,cluster_offset[i].nbr); + log_verbose("cluster_size=%u offset=%lu nbr=%u ", + cluster_offset[i].cluster_size, + cluster_offset[i].offset, + cluster_offset[i].nbr); switch(no_of_cluster2part_type((part_size_in_sectors-cluster_offset[i].offset)/cluster_offset[i].cluster_size)) { case UP_FAT12: diff --git a/src/ntfs_dir.c b/src/ntfs_dir.c index 58b6f903..f374cc3a 100644 --- a/src/ntfs_dir.c +++ b/src/ntfs_dir.c @@ -49,6 +49,9 @@ #ifdef HAVE_MACHINE_ENDIAN_H #include #endif +#ifdef HAVE_ICONV_H +#include +#endif #include /* isalpha */ #include #include "types.h" @@ -139,6 +142,31 @@ static time_t ntfs2utc (s64 ntfstime) return (ntfstime - (NTFS_TIME_OFFSET)) / 10000000; } +#ifdef HAVE_ICONV +static int ntfs_ucstoutf8(iconv_t cd, const ntfschar *ins, int ins_len, char **outs, int outs_len) +{ + const char *inp; + char *outp; + size_t inb_left, outb_left; + if (cd == (iconv_t)(-1)) + return -1; + + outp = *outs; + inp = (const char *) ins; + inb_left = ins_len << 1; // ntfschar is 16-bit + outb_left = outs_len - 1; // reserve 1 byte for NUL + + if (iconv(cd, &inp, &inb_left, &outp, &outb_left) == (size_t)(-1)) + { + // Regardless of the value of errno + log_error("ntfs_ucstoutf8: iconv failed\n"); + return -1; + } + *outp = '\0'; + return 0; +} +#endif + /** * ntfs_td_list_entry * FIXME: Should we print errors as we go along? (AIA) @@ -156,10 +184,18 @@ static int ntfs_td_list_entry( struct ntfs_dir_struct *ls, const ntfschar *name return -1; } +#ifdef HAVE_ICONV + if (ntfs_ucstoutf8(ls->cd, name, name_len, &filename, MAX_PATH) < 0 && + ntfs_ucstombs (name, name_len, &filename, MAX_PATH) < 0) { + log_error("Cannot represent filename in current locale.\n"); + goto free; + } +#else if (ntfs_ucstombs (name, name_len, &filename, MAX_PATH) < 0) { log_error("Cannot represent filename in current locale.\n"); goto free; } +#endif result = 0; /* These are successful */ if (filename[0] == '$') /* system */ @@ -204,7 +240,7 @@ static int ntfs_td_list_entry( struct ntfs_dir_struct *ls, const ntfschar *name { file_data_t *new_file=MALLOC(sizeof(*new_file)); - filename_cpy(new_file->name,filename,(MAX_PATHname)?MAX_PATH:sizeof(new_file->name))); + memcpy(new_file->name,filename,(MAX_PATHname)?MAX_PATH:sizeof(new_file->name))); new_file->prev=ls->current_file; new_file->next=NULL; new_file->filestat.st_dev=0; @@ -319,7 +355,7 @@ static int ntfs_copy(disk_t *disk_car, const partition_t *partition, dir_data_t int l1=strlen(dir_data->local_dir); int l2=strlen(dir_data->current_directory); new_file=MALLOC(l1+l2+1); - memcpy(new_file,dir_data->local_dir,l1); + l1=filename_convert(new_file,dir_data->local_dir,l1+1); filename_convert(new_file+l1,dir_data->current_directory,l2+1); } f_out=create_file(new_file); @@ -378,6 +414,10 @@ static void dir_partition_ntfs_close(dir_data_t *dir_data) free(ls->my_data); if(partition->boot_sector!=0) io_redir_del_redir(disk_car,partition->part_offset); +#ifdef HAVE_ICONV + if (ls->cd != (iconv_t)(-1)) + iconv_close(ls->cd); +#endif free(ls); } #endif @@ -439,6 +479,12 @@ int dir_partition_ntfs_init(disk_t *disk_car, const partition_t *partition, dir_ ls->current_file=NULL; ls->vol=vol; ls->my_data=my_data; +#ifdef HAVE_ICONV + if ((ls->cd = iconv_open("UTF-8", "UTF-16LE")) == (iconv_t)(-1)) + { + log_error("ntfs_ucstoutf8: iconv_open failed\n"); + } +#endif strncpy(dir_data->current_directory,"/",sizeof(dir_data->current_directory)); dir_data->current_inode=FILE_root; dir_data->verbose=verbose; diff --git a/src/ntfs_inc.h b/src/ntfs_inc.h index b1dcf8cc..72e720e7 100644 --- a/src/ntfs_inc.h +++ b/src/ntfs_inc.h @@ -26,5 +26,8 @@ struct ntfs_dir_struct { ntfs_volume *vol; my_data_t *my_data; unsigned long int inode; +#ifdef HAVE_ICONV + iconv_t cd; +#endif }; #endif diff --git a/src/ntfsp.c b/src/ntfsp.c index 563928e0..edca6e14 100644 --- a/src/ntfsp.c +++ b/src/ntfsp.c @@ -30,6 +30,9 @@ #ifdef HAVE_STRING_H #include #endif +#ifdef HAVE_ICONV_H +#include +#endif #include "types.h" #include "common.h" #include "list.h" diff --git a/src/parti386.c b/src/parti386.c index 81d9c4ad..088ba52e 100644 --- a/src/parti386.c +++ b/src/parti386.c @@ -1588,6 +1588,8 @@ static int check_part_i386(disk_t *disk_car,const int verbose,partition_t *parti break; case P_FREEBSD: ret=check_BSD(disk_car,partition,verbose,BSD_MAXPARTITIONS); + if(ret!=0) + { aff_buffer(BUFFER_ADD,"Invalid BSD disklabel\n"); } break; case P_HFS: ret=check_HFS(disk_car,partition,verbose); diff --git a/src/photorec.c b/src/photorec.c index 7ee425a6..3dd25354 100644 --- a/src/photorec.c +++ b/src/photorec.c @@ -992,7 +992,21 @@ int main( int argc, char **argv ) "If you have problems with PhotoRec or bug reports, please contact me.\n"); return 0; } +#ifdef HAVE_SETLOCALE + if(run_setlocale>0) + { + const char *locale; + locale = setlocale (LC_ALL, ""); + if (locale==NULL) { + locale = setlocale (LC_ALL, NULL); + log_error("Failed to set locale, using default '%s'.\n", locale); + } else { + log_info("Using locale '%s'.\n", locale); + } + } +#endif #ifdef HAVE_NCURSES + /* ncurses need locale for correct unicode support */ if(start_ncurses("PhotoRec", argv[0])) return 1; #endif @@ -1010,19 +1024,6 @@ int main( int argc, char **argv ) #endif log_info("\n"); printf("Please wait...\n"); -#ifdef HAVE_SETLOCALE - if(run_setlocale>0) - { - const char *locale; - locale = setlocale (LC_ALL, ""); - if (locale==NULL) { - locale = setlocale (LC_ALL, NULL); - log_error("Failed to set locale, using default '%s'.\n", locale); - } else { - log_info("Using locale '%s'.\n", locale); - } - } -#endif #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(DJGPP) #else #ifdef HAVE_GETEUID diff --git a/src/testdisk.c b/src/testdisk.c index 9460bad7..1f942c6d 100644 --- a/src/testdisk.c +++ b/src/testdisk.c @@ -252,20 +252,6 @@ int main( int argc, char **argv ) delete_list_disk(list_disk); return 0; } -#ifdef HAVE_NCURSES - if(start_ncurses("TestDisk",argv[0])) - return 1; -#endif - if(argc==1) - { - verbose=1; - create_log=ask_log_creation(); - if(create_log>0) - log_open("testdisk.log",(create_log==1?"a":"w"),"TestDisk",argc,argv); - } - log_info("TestDisk %s, Data Recovery Utility, %s\nChristophe GRENIER \nhttp://www.cgsecurity.org\n",VERSION,TESTDISKDATE); - log_info(TESTDISK_OS); - log_info(" (ext2fs lib: %s, ntfs lib: %s, reiserfs lib: %s, ewf lib: %s)\n",td_ext2fs_version(),td_ntfs_version(),td_reiserfs_version(), td_ewf_version()); #ifdef HAVE_SETLOCALE if(run_setlocale>0) { @@ -279,6 +265,21 @@ int main( int argc, char **argv ) } } #endif +#ifdef HAVE_NCURSES + /* ncurses need locale for correct unicode support */ + if(start_ncurses("TestDisk",argv[0])) + return 1; +#endif + if(argc==1) + { + verbose=1; + create_log=ask_log_creation(); + if(create_log>0) + log_open("testdisk.log",(create_log==1?"a":"w"),"TestDisk",argc,argv); + } + log_info("TestDisk %s, Data Recovery Utility, %s\nChristophe GRENIER \nhttp://www.cgsecurity.org\n",VERSION,TESTDISKDATE); + log_info(TESTDISK_OS); + log_info(" (ext2fs lib: %s, ntfs lib: %s, reiserfs lib: %s, ewf lib: %s)\n",td_ext2fs_version(),td_ntfs_version(),td_reiserfs_version(), td_ewf_version()); #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(DJGPP) #else #ifdef HAVE_GETEUID