www.pudn.com > testdisk-6.6.rar > DIR.C
/*
File: dir.c
Copyright (C) 1998-2006 Christophe GRENIER
This software is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write the Free Software Foundation, Inc., 51
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#ifdef HAVE_STRING_H
#include
#endif
#ifdef HAVE_STDLIB_H
#include
#endif
#ifdef HAVE_TIME_H
#include
#endif
#ifdef HAVE_SYS_STAT_H
#include
#endif
#include "types.h"
#include "common.h"
#include "fat.h"
#include "lang.h"
#include "fnctdsk.h"
#include "testdisk.h"
#include "intrf.h"
#include "dir.h"
#include "ext2_dir.h"
#include "fat_dir.h"
#include "ntfs_dir.h"
#include "rfs_dir.h"
static int dir_partition_aux(t_param_disk *disk_car, const t_partition *partition, t_dir_data *dir_data, const unsigned long int inode, const int first_time, char **current_cmd);
static long int dir_aff(t_param_disk *disk_car, const t_partition *partition, t_dir_data *dir_data, const t_file_data*dir_list, const unsigned long int inode, const int first_time, char**current_cmd);
static int copy_dir(t_param_disk *disk_car, const t_partition *partition, t_dir_data *dir_data, const unsigned long int inode);
static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static char ftypelet (unsigned int bits);
static char ftypelet (unsigned int bits)
{
#ifdef LINUX_S_ISBLK
if (LINUX_S_ISBLK (bits))
return 'b';
#endif
if (LINUX_S_ISCHR (bits))
return 'c';
if (LINUX_S_ISDIR (bits))
return 'd';
if (LINUX_S_ISREG (bits))
return '-';
#ifdef LINUX_S_ISFIFO
if (LINUX_S_ISFIFO (bits))
return 'p';
#endif
#ifdef LINUX_S_ISLNK
if (LINUX_S_ISLNK (bits))
return 'l';
#endif
#ifdef LINUX_S_ISSOCK
if (LINUX_S_ISSOCK (bits))
return 's';
#endif
#ifdef LINUX_S_ISMPC
if (LINUX_S_ISMPC (bits))
return 'm';
#endif
#ifdef LINUX_S_ISNWK
if (LINUX_S_ISNWK (bits))
return 'n';
#endif
#ifdef LINUX_S_ISDOOR
if (LINUX_S_ISDOOR (bits))
return 'D';
#endif
#ifdef LINUX_S_ISCTG
if (LINUX_S_ISCTG (bits))
return 'C';
#endif
#ifdef LINUX_S_ISOFD
if (LINUX_S_ISOFD (bits))
/* off line, with data */
return 'M';
#endif
#ifdef LINUX_S_ISOFL
/* off line, with no data */
if (LINUX_S_ISOFL (bits))
return 'M';
#endif
return '?';
}
void mode_string (const unsigned int mode, char *str)
{
str[0] = ftypelet(mode);
str[1] = mode & LINUX_S_IRUSR ? 'r' : '-';
str[2] = mode & LINUX_S_IWUSR ? 'w' : '-';
str[3] = mode & LINUX_S_IXUSR ? 'x' : '-';
str[4] = mode & LINUX_S_IRGRP ? 'r' : '-';
str[5] = mode & LINUX_S_IWGRP ? 'w' : '-';
str[6] = mode & LINUX_S_IXGRP ? 'x' : '-';
str[7] = mode & LINUX_S_IROTH ? 'r' : '-';
str[8] = mode & LINUX_S_IWOTH ? 'w' : '-';
str[9] = mode & LINUX_S_IXOTH ? 'x' : '-';
str[10]='\0';
#ifdef LINUX_S_ISUID
if (mode & LINUX_S_ISUID)
{
if (str[3] != 'x')
/* Set-uid, but not executable by owner. */
str[3] = 'S';
else
str[3] = 's';
}
#endif
#ifdef LINUX_S_ISGID
if (mode & LINUX_S_ISGID)
{
if (str[6] != 'x')
/* Set-gid, but not executable by group. */
str[6] = 'S';
else
str[6] = 's';
}
#endif
#ifdef LINUX_S_ISVTX
if (mode & LINUX_S_ISVTX)
{
if (str[9] != 'x')
/* Sticky, but not executable by others. */
str[9] = 'T';
else
str[9] = 't';
}
#endif
}
int dir_aff_log(const t_param_disk *disk_car, const t_partition *partition, const t_dir_data *dir_data, const t_file_data*dir_list)
{
int test_date=0;
const t_file_data *current_file;
aff_part_rapport(disk_car,partition);
if(dir_data!=NULL)
{
ecrit_rapport("Directory %s\n",dir_data->current_directory);
}
for(current_file=dir_list;current_file!=NULL;current_file=current_file->next)
{
struct tm *tm_p;
char datestr[80];
char str[11];
if(current_file->filestat.st_mtime)
{
tm_p = localtime(¤t_file->filestat.st_mtime);
snprintf(datestr, sizeof(datestr),"%2d-%s-%4d %02d:%02d",
tm_p->tm_mday, monstr[tm_p->tm_mon],
1900 + tm_p->tm_year, tm_p->tm_hour,
tm_p->tm_min);
/* FIXME: a check using current_file->name will be better */
if(1900+tm_p->tm_year>=2000 && 1900+tm_p->tm_year<=2010)
{
test_date=1;
}
} else {
strncpy(datestr, " ",sizeof(datestr));
}
mode_string(current_file->filestat.st_mode,str);
ecrit_rapport("%7lu ",(unsigned long int)current_file->filestat.st_ino);
ecrit_rapport("%s %5u %5u ",
str, (unsigned int)current_file->filestat.st_uid, (unsigned int)current_file->filestat.st_gid);
ecrit_rapport("%7llu", (long long unsigned int)current_file->filestat.st_size);
ecrit_rapport(" %s %s\n", datestr, current_file->name);
}
return test_date;
}
static long int dir_aff(t_param_disk *disk_car, const t_partition *partition, t_dir_data *dir_data, const t_file_data*dir_list, const unsigned long int inode, const int first_time, char **current_cmd)
{
/* Return value
* -1: quit
* 1: back
* other: new inode
* */
int quit=0;
int offset=0;
int pos_num=0;
const t_file_data *current_file;
const t_file_data *pos=dir_list;
aff_copy(dir_data->window);
wmove(dir_data->window,4,0);
aff_part(dir_data->window,AFF_PART_ORDER,disk_car,partition);
mvwaddstr(dir_data->window,5,0,"Use ");
if(first_time==0)
{
if(has_colors())
wbkgdset(dir_data->window,' ' | A_BOLD | COLOR_PAIR(0));
waddstr(dir_data->window, "Left");
if(has_colors())
wbkgdset(dir_data->window,' ' | COLOR_PAIR(0));
waddstr(dir_data->window," arrow to go back, ");
}
if(has_colors())
wbkgdset(dir_data->window,' ' | A_BOLD | COLOR_PAIR(0));
waddstr(dir_data->window,"Right");
if(has_colors())
wbkgdset(dir_data->window,' ' | COLOR_PAIR(0));
waddstr(dir_data->window," arrow to change directory, ");
if(dir_data->copy_file!=NULL)
{
if(has_colors())
wbkgdset(dir_data->window,' ' | A_BOLD | COLOR_PAIR(0));
waddstr(dir_data->window,"c");
if(has_colors())
wbkgdset(dir_data->window,' ' | COLOR_PAIR(0));
waddstr(dir_data->window," to copy, ");
}
if(has_colors())
wbkgdset(dir_data->window,' ' | A_BOLD | COLOR_PAIR(0));
waddstr(dir_data->window,"q");
if(has_colors())
wbkgdset(dir_data->window,' ' | COLOR_PAIR(0));
waddstr(dir_data->window," to quit");
wmove(dir_data->window,6,0);
wdoprintf(dir_data->window,"Directory %s\n",dir_data->current_directory);
do
{
int i;
int car;
for(i=0,current_file=dir_list;(current_file!=NULL) && (inext,i++);
wmove(dir_data->window, 8-1, 4);
wclrtoeol(dir_data->window);
if(offset>0)
wdoprintf(dir_data->window, "Previous");
for(i=offset;(current_file!=NULL) &&((i-offset)next)
{
struct tm *tm_p;
char str[11];
char datestr[80];
wmove(dir_data->window, 8+i-offset, 0);
wclrtoeol(dir_data->window); /* before addstr for BSD compatibility */
if(current_file==pos)
wattrset(dir_data->window,A_STANDOUT);
if(current_file->filestat.st_mtime!=0)
{
tm_p = localtime(¤t_file->filestat.st_mtime);
snprintf(datestr, sizeof(datestr),"%2d-%s-%4d %02d:%02d",
tm_p->tm_mday, monstr[tm_p->tm_mon],
1900 + tm_p->tm_year, tm_p->tm_hour,
tm_p->tm_min);
/* May have to use %d instead of %e */
} else {
strncpy(datestr, " ",sizeof(datestr));
}
mode_string(current_file->filestat.st_mode,str);
wdoprintf(dir_data->window, "%s %5u %5u ",
str, (unsigned int)current_file->filestat.st_uid, (unsigned int)current_file->filestat.st_gid);
wdoprintf(dir_data->window, "%7llu", (long long unsigned int)current_file->filestat.st_size);
/* screen may overlap due to long filename */
wdoprintf(dir_data->window, " %s %s", datestr, current_file->name);
if(current_file==pos)
wattroff(dir_data->window,A_STANDOUT);
}
/* Clear the last line, useful if overlapping */
wmove(dir_data->window,8+i-offset,0);
wclrtoeol(dir_data->window);
wmove(dir_data->window, 8+INTER_DIR, 4);
wclrtoeol(dir_data->window);
if(current_file!=NULL)
wdoprintf(dir_data->window, "Next");
if(dir_list==NULL)
{
wmove(dir_data->window,8,0);
wdoprintf(dir_data->window,"No file found, filesystem seems damaged.");
}
wrefresh(dir_data->window);
/* Using gnome terminal under FC3, TERM=xterm, the screen is not always correct */
wredrawln(dir_data->window,0,getmaxy(dir_data->window)); /* redrawwin def is boggus in pdcur24 */
if(*current_cmd!=NULL)
car='q';
else
car=wgetch(dir_data->window);
wmove(dir_data->window,7,0);
wclrtoeol(dir_data->window);
switch(car)
{
case key_ESC:
case 'q':
case 'M':
quit=1;
break;
case '-':
case KEY_LEFT:
if(first_time==0)
return 1;
break;
}
if(dir_list!=NULL)
{
switch(car)
{
case KEY_UP:
if(pos->prev!=NULL)
{
pos=pos->prev;
pos_num--;
}
if(pos_numnext!=NULL)
{
pos=pos->next;
pos_num++;
}
if(pos_num>=offset+INTER_DIR)
offset++;
break;
case 'p':
case 'P':
case '+':
case ' ':
case KEY_RIGHT:
case '\r':
case '\n':
case KEY_ENTER:
#ifdef PADENTER
case PADENTER:
#endif
if((pos!=NULL) && (LINUX_S_ISDIR(pos->filestat.st_mode)!=0))
{
unsigned long int new_inode=pos->filestat.st_ino;
if((new_inode!=inode) &&(strcmp(pos->name,".")!=0))
{
if(strcmp(pos->name,"..")==0)
return 1;
if(strlen(dir_data->current_directory)+1+strlen(pos->name)+1<=sizeof(dir_data->current_directory))
{
if(strcmp(dir_data->current_directory,"/"))
strcat(dir_data->current_directory,"/");
strcat(dir_data->current_directory,pos->name);
return (long int)new_inode;
}
}
}
break;
case KEY_PPAGE:
for(i=0;(iprev!=NULL);i++)
{
pos=pos->prev;
pos_num--;
if(pos_numnext!=NULL);i++)
{
pos=pos->next;
pos_num++;
if(pos_num>=offset+INTER_DIR)
offset++;
}
break;
case 'c':
if(dir_data->copy_file!=NULL)
{
unsigned int current_directory_namelength=strlen(dir_data->current_directory);
if(strcmp(pos->name,"..")!=0 &&
current_directory_namelength+1+strlen(pos->name)current_directory)-1)
{
if(strcmp(dir_data->current_directory,"/"))
strcat(dir_data->current_directory,"/");
if(strcmp(pos->name,".")!=0)
strcat(dir_data->current_directory,pos->name);
if(dir_data->local_dir==NULL)
{
char *res;
if(LINUX_S_ISDIR(pos->filestat.st_mode)!=0)
res=ask_location("Are you sure you want to copy %s and any files below to the directory %s ? [Y/N]",dir_data->current_directory);
else
res=ask_location("Are you sure you want to copy %s to the directory %s ? [Y/N]",dir_data->current_directory);
// free(dir_data->local_dir);
dir_data->local_dir=res;
}
if(dir_data->local_dir!=NULL)
{
int res=-1;
wmove(dir_data->window,7,0);
wclrtoeol(dir_data->window);
if(has_colors())
wbkgdset(dir_data->window,' ' | A_BOLD | COLOR_PAIR(1));
wdoprintf(dir_data->window,"Copying, please wait...");
if(has_colors())
wbkgdset(dir_data->window,' ' | COLOR_PAIR(0));
wrefresh(dir_data->window);
if(LINUX_S_ISDIR(pos->filestat.st_mode)!=0)
{
res=copy_dir(disk_car, partition, dir_data, (unsigned long int)pos->filestat.st_ino);
}
else if(LINUX_S_ISREG(pos->filestat.st_mode)!=0)
{
res=dir_data->copy_file(disk_car, partition, dir_data, (unsigned long int)pos->filestat.st_ino);
}
wmove(dir_data->window,7,0);
wclrtoeol(dir_data->window);
if(res<0)
{
if(has_colors())
wbkgdset(dir_data->window,' ' | A_BOLD | COLOR_PAIR(1));
wdoprintf(dir_data->window,"Copy failed!");
}
else
{
if(has_colors())
wbkgdset(dir_data->window,' ' | A_BOLD | COLOR_PAIR(2));
if(res>0)
wdoprintf(dir_data->window,"Copy done! (Failed to copy some files)");
else
wdoprintf(dir_data->window,"Copy done!");
}
if(has_colors())
wbkgdset(dir_data->window,' ' | COLOR_PAIR(0));
}
dir_data->current_directory[current_directory_namelength]='\0';
}
}
break;
}
}
} while(quit==0);
return -1;
}
void dir_aff_entry(WINDOW *window, struct file_info *dir_info)
{
struct tm *tm_p;
char str[11];
char datestr[80];
if(dir_info->stat.st_mtime!=0)
{
tm_p = localtime(&dir_info->stat.st_mtime);
snprintf(datestr, sizeof(datestr),"%2d-%s-%4d %02d:%02d",
tm_p->tm_mday, monstr[tm_p->tm_mon],
1900 + tm_p->tm_year, tm_p->tm_hour,
tm_p->tm_min);
/* May have to use %d instead of %e */
} else {
strncpy(datestr, " ",sizeof(datestr));
}
mode_string(dir_info->stat.st_mode,str);
wdoprintf(window, "%s %5u %5u ",
str, (unsigned int)dir_info->stat.st_uid, (unsigned int)dir_info->stat.st_gid);
wdoprintf(window, "%7llu", (long long unsigned int)dir_info->stat.st_size);
/* screen may overlap due to long filename */
wdoprintf(window, " %s %s", datestr, dir_info->name);
}
void delete_list_file(t_file_data *file_list)
{
t_file_data *current_file=file_list;
while(current_file!=NULL)
{
t_file_data *next=current_file->next;
free(current_file);
current_file=next;
}
}
int dir_partition_aff(t_param_disk *disk_car, const t_partition *partition, t_dir_data *dir_data, const unsigned long int inode, char **current_cmd)
{
if(dir_data==NULL)
return -1;
return dir_partition_aux(disk_car,partition,dir_data,inode,1,current_cmd);
}
static int dir_partition_aux(t_param_disk *disk_car, const t_partition *partition, t_dir_data *dir_data, const unsigned long int inode, const int first_time, char**current_cmd)
{
t_file_data *dir_list;
long int new_inode;
if(dir_data->debug>0)
ecrit_rapport("\ndir_partition inode=%ld\n",inode);
dir_list=dir_data->get_dir(disk_car,partition,dir_data,inode);
dir_aff_log(disk_car, partition, dir_data, dir_list);
do
{
unsigned int current_directory_namelength=strlen(dir_data->current_directory);
new_inode=dir_aff(disk_car,partition,dir_data,dir_list,inode,first_time,current_cmd);
if(new_inode==0 || new_inode>1)
{
if(dir_partition_aux(disk_car, partition, dir_data, (unsigned long int)new_inode,0,current_cmd)<0)
{ /* quit */
delete_list_file(dir_list);
return -1;
}
/* back */
dir_data->current_directory[current_directory_namelength]='\0';
}
} while(new_inode==0 || new_inode>1);
delete_list_file(dir_list);
return new_inode;
}
static int copy_dir(t_param_disk *disk_car, const t_partition *partition, t_dir_data *dir_data, const unsigned long int inode)
{
unsigned int file_failed=0;
unsigned int file_copied=0;
t_file_data *dir_list;
unsigned int current_directory_namelength=strlen(dir_data->current_directory);
t_file_data *current_file;
if(dir_data->get_dir==NULL || dir_data->copy_file==NULL)
return -1;
ecrit_rapport("copy_dir %s\n",dir_data->current_directory);
{
char *dir_name=MALLOC(strlen(dir_data->local_dir)+strlen(dir_data->current_directory)+1);
strcpy(dir_name,dir_data->local_dir);
strcat(dir_name,dir_data->current_directory);
create_dir(dir_name,1);
free(dir_name);
}
dir_list=dir_data->get_dir(disk_car,partition,dir_data,inode);
// dir_aff_log(disk_car, partition, dir_data, dir_list);
for(current_file=dir_list;current_file!=NULL;current_file=current_file->next)
{
if(strlen(dir_data->current_directory)+1+strlen(current_file->name)current_directory)-1)
{
if(strcmp(dir_data->current_directory,"/"))
strcat(dir_data->current_directory,"/");
strcat(dir_data->current_directory,current_file->name);
if(LINUX_S_ISDIR(current_file->filestat.st_mode)!=0)
{
if((unsigned long int)current_file->filestat.st_ino!=inode &&
strcmp(current_file->name,"..")!=0 && strcmp(current_file->name,".")!=0)
copy_dir(disk_car, partition, dir_data, (unsigned long int)current_file->filestat.st_ino);
}
else if(LINUX_S_ISREG(current_file->filestat.st_mode)!=0)
{
// ecrit_rapport("copy_file %s\n",dir_data->current_directory);
if(dir_data->copy_file(disk_car, partition, dir_data, (unsigned long int)current_file->filestat.st_ino))
file_failed++;
else
file_copied++;
}
dir_data->current_directory[current_directory_namelength]='\0';
}
}
delete_list_file(dir_list);
return (file_copied>0?(file_failed>0?1:0):-1);
}
FILE *create_file(const char *filename)
{
FILE *f_out;
f_out=fopen(filename,"wb");
if(!f_out)
{
create_dir(filename,0);
f_out=fopen(filename,"wb");
}
return f_out;
}