diff options
author | Christophe Grenier <grenier@cgsecurity.org> | 2009-01-14 22:13:47 +0100 |
---|---|---|
committer | Christophe Grenier <grenier@cgsecurity.org> | 2009-01-14 22:13:47 +0100 |
commit | 1650fe5b8b6cea638c280df13605aea816718a00 (patch) | |
tree | fed11bd9361236aba47157d859607c109db05814 /src/dirn.c | |
parent | 56e1c29b2c0614b0b3230946d72e1eaf37618bcc (diff) |
Split ncurses text interface from functions
Diffstat (limited to 'src/dirn.c')
-rw-r--r-- | src/dirn.c | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/src/dirn.c b/src/dirn.c new file mode 100644 index 0000000..da7e7df --- /dev/null +++ b/src/dirn.c @@ -0,0 +1,463 @@ +/* + + File: dirn.c + + Copyright (C) 1998-2009 Christophe GRENIER <grenier@cgsecurity.org> + + 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 <config.h> +#endif + +#ifdef HAVE_NCURSES +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#include "types.h" +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif +#include <errno.h> +#include "common.h" +#include "fat.h" +#include "lang.h" +#include "fnctdsk.h" +#include "testdisk.h" +#include "intrf.h" +#include "intrfn.h" +#include "dir.h" +#include "ext2_dir.h" +#include "fat_dir.h" +#include "ntfs_dir.h" +#include "rfs_dir.h" +#include "log.h" +#include "log_part.h" +#include "dirn.h" +#include "askloc.h" + +extern const char *monstr[]; + +static int dir_partition_aux(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode, const unsigned int depth, char **current_cmd); +static long int dir_aff_ncurses(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const file_data_t*dir_list, const unsigned long int inode, const unsigned int depth); +static int copy_dir(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const file_data_t *dir); + +#define INTER_DIR (LINES-25+16) + +static long int dir_aff_ncurses(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const file_data_t*dir_list, const unsigned long int inode, const unsigned int depth) +{ + /* Return value + * -1: quit + * 1: back + * other: new inode + * */ + int quit=0; + WINDOW *window=(WINDOW*)dir_data->display; + do + { + int offset=0; + int pos_num=0; + const file_data_t *current_file; + const file_data_t *pos=dir_list; + int old_LINES=LINES; + aff_copy(window); + wmove(window,3,0); + aff_part(window, AFF_PART_ORDER|AFF_PART_STATUS, disk, partition); + wmove(window,4,0); + wprintw(window,"Directory %s\n",dir_data->current_directory); + do + { + int i; + int car; + for(i=0,current_file=dir_list;(current_file!=NULL) && (i<offset);current_file=current_file->next,i++); + for(i=offset;(current_file!=NULL) &&((i-offset)<INTER_DIR);i++,current_file=current_file->next) + { + char str[11]; + char datestr[80]; + wmove(window, 6+i-offset, 0); + wclrtoeol(window); /* before addstr for BSD compatibility */ + if(current_file==pos) + wattrset(window, A_REVERSE); + if((current_file->status&FILE_STATUS_DELETED)!=0 && has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(1)); + if(current_file->stat.st_mtime!=0) + { + struct tm *tm_p; + tm_p = localtime(¤t_file->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(current_file->stat.st_mode,str); + wprintw(window, "%s %5u %5u ", + str, (unsigned int)current_file->stat.st_uid, (unsigned int)current_file->stat.st_gid); + wprintw(window, "%7llu", (long long unsigned int)current_file->stat.st_size); + /* screen may overlap due to long filename */ + wprintw(window, " %s %s", datestr, current_file->name); + if((current_file->status&FILE_STATUS_DELETED)!=0 && has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(0)); + if(current_file==pos) + wattroff(window, A_REVERSE); + } + wmove(window, 6-1, 51); + wclrtoeol(window); + if(offset>0) + wprintw(window, "Previous"); + /* Clear the last line, useful if overlapping */ + wmove(window,6+i-offset,0); + wclrtoeol(window); + wmove(window, 6+INTER_DIR, 51); + wclrtoeol(window); + if(current_file!=NULL) + wprintw(window, "Next"); + if(dir_list==NULL) + { + wmove(window,6,0); + wprintw(window,"No file found, filesystem seems damaged."); + } + /* Redraw the bottom of the screen everytime because very long filenames may have corrupt it*/ + mvwaddstr(window,LINES-2,0,"Use "); + if(depth>0) + { + if(has_colors()) + wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0)); + waddstr(window, "Left"); + if(has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(0)); + waddstr(window," arrow to go back, "); + } + if(has_colors()) + wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0)); + waddstr(window,"Right"); + if(has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(0)); + waddstr(window," arrow to change directory, "); + if(dir_data->copy_file!=NULL) + { + if(has_colors()) + wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0)); + waddstr(window,"c"); + if(has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(0)); + waddstr(window," to copy, "); + } + wmove(window,LINES-1,4); + if((dir_data->capabilities&CAPA_LIST_DELETED)!=0) + { + if(has_colors()) + wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0)); + waddstr(window,"h"); + if(has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(0)); + if((dir_data->param&FLAG_LIST_DELETED)==0) + waddstr(window," to unhide deleted files, "); + else + waddstr(window," to hide deleted files, "); + } + if(has_colors()) + wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0)); + waddstr(window,"q"); + if(has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(0)); + waddstr(window," to quit"); + wrefresh(window); + /* Using gnome terminal under FC3, TERM=xterm, the screen is not always correct */ + wredrawln(window,0,getmaxy(window)); /* redrawwin def is boggus in pdcur24 */ + car=wgetch(window); + wmove(window,5,0); + wclrtoeol(window); + switch(car) + { + case key_ESC: + case 'q': + case 'M': + quit=1; + break; + case '-': + case KEY_LEFT: + case '4': + if(depth>0) + return 1; + break; + case 'h': + if((dir_data->capabilities&CAPA_LIST_DELETED)!=0) + dir_data->param^=FLAG_LIST_DELETED; + return inode; + } + if(dir_list!=NULL) + { + switch(car) + { + case KEY_UP: + case '8': + if(pos->prev!=NULL) + { + pos=pos->prev; + pos_num--; + } + break; + case KEY_DOWN: + case '2': + if(pos->next!=NULL) + { + pos=pos->next; + pos_num++; + } + break; + case 'p': + case 'P': + case '+': + case ' ': + case KEY_RIGHT: + case '\r': + case '\n': + case '6': + case KEY_ENTER: +#ifdef PADENTER + case PADENTER: +#endif + if((pos!=NULL) && (LINUX_S_ISDIR(pos->stat.st_mode)!=0)) + { + unsigned long int new_inode=pos->stat.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;(i<INTER_DIR-1)&&(pos->prev!=NULL);i++) + { + pos=pos->prev; + pos_num--; + } + break; + case KEY_NPAGE: + for(i=0;(i<INTER_DIR-1)&&(pos->next!=NULL);i++) + { + pos=pos->next; + pos_num++; + } + break; + case 'c': + if(dir_data->copy_file!=NULL) + { + const unsigned int current_directory_namelength=strlen(dir_data->current_directory); + if(strcmp(pos->name,"..")!=0 && + current_directory_namelength+1+strlen(pos->name)<sizeof(dir_data->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) + { + if(LINUX_S_ISDIR(pos->stat.st_mode)!=0) + dir_data->local_dir=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 + dir_data->local_dir=ask_location("Are you sure you want to copy %s to the directory %s ? [Y/N]", + dir_data->current_directory); + } + if(dir_data->local_dir!=NULL) + { + int res=-1; + wmove(window,5,0); + wclrtoeol(window); + if(has_colors()) + wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(1)); + wprintw(window,"Copying, please wait..."); + if(has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(0)); + wrefresh(window); + if(LINUX_S_ISDIR(pos->stat.st_mode)!=0) + { + res=copy_dir(disk, partition, dir_data, pos); + } + else if(LINUX_S_ISREG(pos->stat.st_mode)!=0) + { + res=dir_data->copy_file(disk, partition, dir_data, pos); + } + wmove(window,5,0); + wclrtoeol(window); + if(res < -1) + { + if(has_colors()) + wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(1)); + wprintw(window,"Copy failed!"); + } + else + { + if(has_colors()) + wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(2)); + if(res < 0) + wprintw(window,"Copy done! (Failed to copy some files)"); + else + wprintw(window,"Copy done!"); + } + if(has_colors()) + wbkgdset(window,' ' | COLOR_PAIR(0)); + } + dir_data->current_directory[current_directory_namelength]='\0'; + } + } + break; + } + if(pos_num<offset) + offset=pos_num; + if(pos_num>=offset+INTER_DIR) + offset=pos_num-INTER_DIR+1; + } + } while(quit==0 && old_LINES==LINES); + } while(quit==0); + return -1; +} + +static int dir_partition_aux(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode, const unsigned int depth, char**current_cmd) +{ +#define MAX_DIR_NBR 256 + static unsigned long int inode_known[MAX_DIR_NBR]; + if(depth==MAX_DIR_NBR) + return 1; /* subdirectories depth is too high => Back */ + if(dir_data->verbose>0) + { + log_info("\ndir_partition inode=%lu\n",inode); + log_partition(disk, partition); + } + while(1) + { + const unsigned int current_directory_namelength=strlen(dir_data->current_directory); + long int new_inode=-1; /* Quit */ + file_data_t *dir_list; + /* Not perfect for FAT32 root cluster */ + inode_known[depth]=inode; + dir_list=dir_data->get_dir(disk, partition, dir_data, inode); + dir_aff_log(disk, partition, dir_data, dir_list); + if(*current_cmd!=NULL) + { + dir_data->current_directory[current_directory_namelength]='\0'; + delete_list_file(dir_list); + return -1; /* Quit */ + } + new_inode=dir_aff_ncurses(disk, partition, dir_data,dir_list,inode,depth); + if(new_inode==-1 || new_inode==1) /* -1:Quit or 1:Back */ + { + delete_list_file(dir_list); + return new_inode; + } + if(new_inode>=2) + { + unsigned int new_inode_ok=1; + unsigned int i; + for(i=0;i<=depth && new_inode_ok!=0;i++) + if(new_inode==inode_known[i]) /* Avoid loop */ + new_inode_ok=0; + if(new_inode_ok>0) + { + dir_partition_aux(disk, partition, dir_data, (unsigned long int)new_inode, depth+1, current_cmd); + } + } + /* restore current_directory name */ + dir_data->current_directory[current_directory_namelength]='\0'; + delete_list_file(dir_list); + } +} + +int dir_partition_aff(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode, char **current_cmd) +{ + if(dir_data==NULL) + return -1; + return dir_partition_aux(disk, partition, dir_data, inode, 0, current_cmd); +} + +/* +Returns +-2: no file copied +-1: failed to copy some files +0: all files has been copied +*/ +static int copy_dir(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const file_data_t *dir) +{ + file_data_t *dir_list; + const unsigned int current_directory_namelength=strlen(dir_data->current_directory); + file_data_t *current_file; + char *dir_name; + int copy_bad=0; + int copy_ok=0; + if(dir_data->get_dir==NULL || dir_data->copy_file==NULL) + return -2; + dir_name=mkdir_local(dir_data->local_dir, dir_data->current_directory); + dir_list=dir_data->get_dir(disk, partition, dir_data, (const unsigned long int)dir->stat.st_ino); + for(current_file=dir_list;current_file!=NULL;current_file=current_file->next) + { + dir_data->current_directory[current_directory_namelength]='\0'; + if(current_directory_namelength+1+strlen(current_file->name)<sizeof(dir_data->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->stat.st_mode)!=0) + { + int tmp=0; + if(current_file->stat.st_ino != dir->stat.st_ino && + strcmp(current_file->name,"..")!=0 && strcmp(current_file->name,".")!=0) + tmp=copy_dir(disk, partition, dir_data, current_file); + if(tmp>=-1) + copy_ok=1; + if(tmp<0) + copy_bad=1; + } + else if(LINUX_S_ISREG(current_file->stat.st_mode)!=0) + { +// log_trace("copy_file %s\n",dir_data->current_directory); + int tmp; + tmp=dir_data->copy_file(disk, partition, dir_data, current_file); + if(tmp==0) + copy_ok=1; + else + copy_bad=1; + } + } + } + dir_data->current_directory[current_directory_namelength]='\0'; + delete_list_file(dir_list); + set_date(dir_name, dir->stat.st_atime, dir->stat.st_mtime); + free(dir_name); + return (copy_bad>0?(copy_ok>0?-1:-2):0); +} + +#endif |