📄 de.c
字号:
/****************************************************************//* *//* de.c *//* *//* Main loop of the "Disk editor". *//* *//****************************************************************//* origination 1989-Jan-15 Terrence W. Holm *//****************************************************************/#include <minix/config.h>#include <sys/types.h>#include <sys/dir.h>#include <sys/stat.h>#include <sys/wait.h>#include <ctype.h>#include <errno.h>#undef ERROR /* arrgghh, errno.h has this pollution */#include <fcntl.h>#include <limits.h>#include <signal.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <minix/const.h>#include <minix/type.h>#include "../../fs/const.h"#include "../../fs/type.h"#include "../../fs/inode.h"#include "de.h"static char copyright[] = "de (c) Terrence W. Holm 1989";_PROTOTYPE(void Push , (de_state *s ));_PROTOTYPE(int Get_Base , (int *base ));_PROTOTYPE(int Get_Filename , (de_state *s ));_PROTOTYPE(int Get_Count , (char *units , unsigned long *result ));_PROTOTYPE(void Exec_Shell , (void));_PROTOTYPE(void Sigint , (int));/****************************************************************//* *//* main() *//* *//* Initialize. Handle the "-r" recovery option if *//* specified, else enter the main processing loop. *//* *//****************************************************************/void main( argc, argv ) int argc; char *argv[]; { static de_state s; /* it is safer not to put it on the stack * and some things probably now rely on zero * initialization */ char *command_name = argv[0]; int recover = 0; s.device_mode = O_RDONLY; /* Parse arguments */ if ( argc == 3 && strcmp( argv[1], "-r" ) == 0 ) { recover = 1; --argc; ++argv; } else if ( argc == 3 && strcmp( argv[1], "-w" ) == 0 ) { s.device_mode = O_RDWR; --argc; ++argv; } if ( argc != 2 || *argv[1] == '-' ) { fprintf( stderr, "Usage: %s [-w] /dev/device\n", command_name ); fprintf( stderr, " %s -r lost_file_name\n", command_name ); exit( 1 ); } /* Set the effective id to the real id. This eliminates */ /* any increase in privilege done by a set-uid bit on the */ /* executable file. We want to be "root" for recovering */ /* files, because we must be able to read the device. */ /* However, in normal usage, de(1) should not let just */ /* anyone look at a file system, thus we drop the privilege. */ /* */ /* NOTE: There is a security hole when using "-r" with a */ /* set-uid de(1). Do not use set-uid root if there is any */ /* way to externally access your Minix system. */ if ( ! recover ) { setuid( getuid() ); setgid( getgid() ); } /* Set terminal characteristics, and ^C interrupt handler */ Save_Term(); if ( signal( SIGINT, SIG_IGN ) != SIG_IGN ) { signal( SIGINT, Sigint ); signal( SIGQUIT, Sigint ); } Set_Term(); if ( ! Init_Termcap() ) Error( "Requires a termcap entry" ); /* Get the device file name. If recovering, also open an output file. */ if ( recover ) { char *dir_name; char *file_name; struct stat device_stat; struct stat tmp_stat; /* Split the path name into a directory and a file name. */ if ( strlen(argv[1]) > MAX_STRING ) Error( "Path name too long" ); if ( ! Path_Dir_File( argv[1], &dir_name, &file_name ) ) Error( "Recover aborted" ); /* Find the device holding the directory. */ if ( (s.device_name = File_Device( dir_name )) == NULL ) Error( "Recover aborted" ); /* The output file will be in /tmp with the same file name. */ strcpy( s.file_name, TMP ); strcat( s.file_name, "/" ); strcat( s.file_name, file_name ); /* Make sure /tmp is not on the same device as the file we */ /* are trying to recover (we don't want to use up the free */ /* i-node and blocks before we get a chance to recover them). */ if ( stat( s.device_name, &device_stat ) == -1 ) Error( "Can not stat(2) device %s", s.device_name ); if ( stat( TMP, &tmp_stat ) == -1 ) Error( "Can not stat(2) directory %s", TMP ); if ( device_stat.st_rdev == tmp_stat.st_dev ) Error( "Will not recover files on the same device as %s", TMP ); if ( access( s.file_name, F_OK ) == 0 ) Error( "Will not overwrite file %s", s.file_name ); /* Open the output file. */ if ( (s.file_f = fopen( s.file_name, "w" )) == NULL ) Error( "Can not open file %s", s.file_name ); /* Don't let anyone else look at the recovered file */ chmod( s.file_name, 0700 ); /* If running as root then change the owner of the */ /* restored file. If not running as root then the */ /* chown(2) will fail. */ chown( s.file_name, getuid(), getgid() ); } else { s.device_name = argv[1]; s.file_name[ 0 ] = '\0'; } /* Open the device file. */ { struct stat device_stat; off_t size; if ( stat( s.device_name, &device_stat ) == -1 ) Error( "Can not find file %s", s.device_name ); if ( (device_stat.st_mode & S_IFMT) != S_IFBLK && (device_stat.st_mode & S_IFMT) != S_IFREG ) Error( "Can only edit block special or regular files" ); if ( (s.device_d = open( s.device_name, s.device_mode )) == -1 ) Error( "Can not open %s", s.device_name ); if ( (size = lseek( s.device_d, 0L, SEEK_END )) == -1 ) Error( "Error seeking %s", s.device_name ); if ( size % K != 0 ) { Warning( "Device size is not a multiple of 1024" ); Warning( "The (partial) last block will not be accessible" ); } } /* Initialize the rest of the state record */ s.mode = WORD; s.output_base = 10; s.search_string[ 0 ] = '\0'; { int i; for ( i = 0; i < MAX_PREV; ++i ) { s.prev_addr[ i ] = 0L; s.prev_mode[ i ] = WORD; } } sync(); Read_Super_Block( &s ); Read_Bit_Maps( &s ); s.address = 0L; /* Recover mode basically performs an 'x' and an 'X' */ if ( recover ) { ino_t inode = Find_Deleted_Entry( &s, argv[1] ); off_t size; if ( inode == 0 ) { unlink( s.file_name ); Error( "Recover aborted" ); } s.address = ( (long) s.first_data - s.inode_blocks ) * K + (long) (inode - 1) * s.inode_size; Read_Block( &s, s.buffer ); /* Have found the lost i-node, now extract the blocks. */ if ( (size = Recover_Blocks( &s )) == -1L ) { unlink( s.file_name ); Error( "Recover aborted" ); } Reset_Term(); printf( "Recovered %ld bytes, written to file %s\n", size, s.file_name ); exit( 0 ); } /* Enter the main loop, first time redraw the screen */ { int rc = REDRAW; do { if ( rc == REDRAW ) { Read_Block( &s, s.buffer ); Draw_Screen( &s ); s.last_addr = s.address; Draw_Pointers( &s ); } else if ( rc == REDRAW_POINTERS ) { s.offset = (unsigned) (s.address & ~ K_MASK); Draw_Pointers( &s ); } else if ( rc == ERROR ) { Erase_Prompt(); putchar( BELL ); } } while ( (rc = Process( &s, Arrow_Esc(Get_Char()) )) != EOF ); } /* If there is an open output file that was never written to */ /* then remove its directory entry. This occurs when no 'w' */ /* or 'W' command occurred between a 'c' command and exiting */ /* the program. */ if ( s.file_name[0] != '\0' && ! s.file_written ) unlink( s.file_name ); Reset_Term(); /* Restore terminal characteristics */ exit( 0 ); }/****************************************************************//* *//* Get_Base( base ) *//* *//* Get a new base value. *//* Returns REDRAW or ERROR. *//* *//****************************************************************/int Get_Base( base ) int *base; { switch ( Get_Char() ) { case 'h' : *base = 16; break; case 'd' : *base = 10; break; case 'o' : *base = 8; break; case 'b' : *base = 2; break; default : return( ERROR ); } return( REDRAW ); }/****************************************************************//* *//* Process( state, input_char ) *//* *//* Determine the function requested by the *//* input character. Returns OK, REDRAW, *//* REDRAW_POINTERS, ERROR or EOF. *//* *//****************************************************************/int Process( s, c ) de_state *s; int c; { switch ( c ) { case 'b' : /* Back up one block */ case ESC_PGUP : if ( s->address == 0 ) return( ERROR ); s->address = (s->address - K) & K_MASK; return( REDRAW ); case 'B' : /* Back up to home */ case ESC_HOME : if ( s->address == 0 ) return( OK ); Push( s ); s->address = 0L; return( REDRAW ); case 'c' : /* Change file name */ { int rc = Get_Filename( s ); return( rc == OK ? REDRAW : rc ); } case 'd' : /* Down */ case ESC_DOWN : { s->last_addr = s->address; switch ( s->mode ) { case WORD : s->address += 2; if ( (s->address & PAGE_MASK) == 0 ) return( REDRAW ); return( REDRAW_POINTERS ); case BLOCK : s->address += 64; if ( (s->last_addr & K_MASK) != (s->address & K_MASK) ) return( REDRAW ); return( REDRAW_POINTERS ); case MAP : s->address += 256; return( REDRAW ); default : Error( "Internal fault (mode)" ); } } case 'f' : /* Forward one block */ case ' ' : case ESC_PGDN : if ( s->block == s->device_size - 1 ) return( ERROR ); s->address = (s->address + K) & K_MASK; return( REDRAW ); case 'F' : /* Forward to end */ case ESC_END : { off_t last_block = ( (long) s->device_size - 1 ) * K; if ( s->address == last_block ) return( OK ); Push( s ); s->address = last_block; return( REDRAW ); } case 'g' : /* Goto block */ { unsigned long block; if ( Get_Count( "Block?", &block ) ) { if ( block >= s->zones ) { Warning( "Block number too large" ); return( REDRAW ); } Push( s ); s->address = (off_t) block * K; return( REDRAW ); } else return( ERROR ); } case 'G' : /* Goto block indirect */ { unsigned block = *( (word_t *) &s->buffer[ s->offset ] ); if ( s->mode != WORD ) { Warning( "Must be in visual mode \"word\"" ); return( REDRAW ); } if ( block >= s->zones ) { Warning( "Block number too large" ); return( REDRAW ); } Push( s ); s->mode = BLOCK; s->address = (long) block * K; return( REDRAW ); } case 'h' : /* Help */ case '?' : Draw_Help_Screen( s ); Wait_For_Key(); return( REDRAW ); case 'i' : /* Goto i-node */ { unsigned long inode; if ( Get_Count( "I-node?", &inode ) ) { if ( inode < 1 || inode > s->inodes ) { Warning( "Illegal i-node number" ); return( REDRAW ); } Push( s ); s->mode = WORD; s->address = (off_t) (s->first_data - s->inode_blocks) * K + (off_t) (inode - 1) * s->inode_size; return( REDRAW ); } else return( ERROR ); } case 'I' : /* Filename to i-node */ { ino_t inode; char *filename; Draw_Prompt( "File name?" ); filename = Get_Line(); if ( filename == NULL || filename[0] == '\0' ) return( ERROR ); inode = Find_Inode( s, filename ); if ( inode ) { Push( s ); s->mode = WORD; s->address = ( (long) s->first_data - s->inode_blocks ) * K + (long) (inode - 1) * s->inode_size; } return( REDRAW ); } case 'l' : /* Left */ case ESC_LEFT : { s->last_addr = s->address; switch ( s->mode ) { case WORD : s->address = s->address - 32; return( REDRAW ); case BLOCK : s->address -= 1; if ( (s->last_addr & K_MASK) != (s->address & K_MASK) ) return( REDRAW ); return( REDRAW_POINTERS ); case MAP : s->address -= 4; if ( (s->last_addr & ~ MAP_MASK) != (s->address & ~ MAP_MASK) ) return( REDRAW ); return( REDRAW_POINTERS ); default : Error( "Internal fault (mode)" ); } } case 'm' : /* Invoke a Minix shell */ Reset_Term(); Exec_Shell(); Set_Term(); return( REDRAW ); case 'n' : /* Search for next */ { off_t addr; if ( s->search_string[0] == '\0' ) { Warning( "No search string defined" ); return( REDRAW ); } Draw_Prompt( "Searching..." ); if ( (addr = Search( s, s->search_string )) == -1L ) { Warning( "Search string not found" ); Wait_For_Key(); return( REDRAW ); } Push( s ); s->address = addr; return( REDRAW );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -