add directory study
This commit is contained in:
13
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/Makefile
Normal file
13
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
CFLAGS = -F -D_MINIX -D_POSIX_SOURCE
|
||||
DEOBJ = de.s de_stdin.s de_stdout.s de_diskio.s de_recover.s
|
||||
|
||||
de: $(DEOBJ)
|
||||
cc -i -T. $(DEOBJ) -o de
|
||||
chmem =30000 de
|
||||
echo "chmod 755 de; chown bin de; chgrp bin de"
|
||||
|
||||
$(DEOBJ): de.h
|
||||
|
||||
|
||||
clean:
|
||||
@rm -f *.bak *.s de
|
||||
@@ -0,0 +1,11 @@
|
||||
CFLAGS = -O -DATARI_ST
|
||||
DEOBJ = de.o de_stdin.o de_stdout.o de_diskio.o de_recover.o
|
||||
|
||||
de: $(DEOBJ)
|
||||
cc $(DEOBJ) -o de
|
||||
chmem =20000 de
|
||||
chmod 4755 de
|
||||
chown root de
|
||||
chgrp bin de
|
||||
|
||||
$(DEOBJ): de.h
|
||||
156
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/README
Normal file
156
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/README
Normal file
@@ -0,0 +1,156 @@
|
||||
de - A Minix Disk Editor
|
||||
|
||||
Terrence W. Holm, Jan. 1989
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
The de(1) disk editor allows a system administrator to
|
||||
look at and modify a Minix file system device. Commands
|
||||
allow movement throughout a file system device, displaying
|
||||
information in a couple of formats, writing blocks from
|
||||
the device onto another file, and rewriting words on the
|
||||
disk.
|
||||
|
||||
A few changes to the Minix file system aid recovering files.
|
||||
I-node numbers are retained in directory entries now (they
|
||||
get moved to the end). And all the i-node information is not
|
||||
zeroed-out when a file is unlinked. So, after a file is
|
||||
accidently rm(1)'ed, you can find the old i-node, and then
|
||||
manually (or automatically) go to each of the freed blocks
|
||||
and write them to a new file.
|
||||
|
||||
|
||||
USES FOR THE DISK EDITOR
|
||||
|
||||
1) EDUCATION. Students can look at a file system in
|
||||
a painless manner. For example you don't have to
|
||||
use od(1) to look at the zone numbers in i-nodes.
|
||||
|
||||
A simple assignment is to change the size of an un-mounted
|
||||
floppy disk file system from 360 to 300 blocks. (A more
|
||||
difficult assignment is to explain why this works, even
|
||||
though fsck(1) and df(1) do not report the correct number
|
||||
of free blocks. :-)
|
||||
|
||||
2) ADMINISTRATION. You can visually check inconsistencies
|
||||
reported by fsck(1) before letting fsck(1) fix them.
|
||||
You can change any word on the disk, this greatly simplifies
|
||||
editing file system information. For example, changing the
|
||||
size of a block special device is actually fun, no more
|
||||
"blind" writing to your partitions.
|
||||
|
||||
Bit maps can be displayed with 2048 "bits" per screen,
|
||||
(on the IBM/PC console), see how your zones are allocated!
|
||||
|
||||
3) RECOVERING LOST FILES. You can search a disk for an ASCII
|
||||
string, once found, the block can be written out to a file.
|
||||
|
||||
A one line change to fs/path.c allows users to get the i-node
|
||||
number for a file after it has been removed from a directory.
|
||||
|
||||
Another couple lines changed in the file system keep the
|
||||
i-node information available until the i-node is reused
|
||||
(normally this information is zeroed out when an i-node is
|
||||
released.) This allows a de(1) user to go to a released
|
||||
i-node, get all the block numbers, go to these blocks and
|
||||
write them back to a new file.
|
||||
|
||||
The whole recovery process is automated by running "de -r file".
|
||||
So, IF a file is unlink(2)'ed (eg. "rm file"), AND IF no one
|
||||
allocates a new i-node or block in the mean-time, THEN you
|
||||
can recover the file.
|
||||
|
||||
|
||||
RECOVERY SECURITY
|
||||
|
||||
Normally Minix hard disk partitions are r/w only by the super-user,
|
||||
and floppy disks are r/w by anyone. This means that only "root"
|
||||
can look at hard disk partitions, but others can use de(1) to play
|
||||
with their floppy disks.
|
||||
|
||||
When recovering files ("de -r file"), a user requires access to
|
||||
the major file system partitions. This can be done by:
|
||||
|
||||
(a) Give everyone access to the hard disks. DON'T DO THIS, it
|
||||
defeats all the file system protection we already have.
|
||||
|
||||
(b) Make de(1) set-uid "root". This is the way to go, IF you
|
||||
are running a Minix system that has NO ACCESS from the
|
||||
outside. This allows anyone to execute "de -r file", but only
|
||||
root to use "de /dev/hd3". De(1) does some checking when
|
||||
retrieving lost blocks, eg. making sure they really are
|
||||
free blocks and making sure the user owned the i-node.
|
||||
BUT, file system information has been lost when the file
|
||||
was unlink(2)'ed, so de(1) can not be 100% sure that a
|
||||
recovered block really belonged to the user. THIS IS A
|
||||
SECURITY HOLE. [Since the only access to my machine is from
|
||||
observable terminals and their associated humans, I run
|
||||
de(1) as set-uid root.]
|
||||
|
||||
(c) Keep the disks rw-------, and don't set-uid de(1). This
|
||||
means that only the super-user can recover lost files.
|
||||
So, if you accidently "rm", you must tell the system
|
||||
administrator to "su" and recover your file, (be sure to
|
||||
inform the other users to stop whatever they are doing
|
||||
until the file is restored).
|
||||
|
||||
|
||||
INSTALLATION
|
||||
|
||||
- Install de.1 in /usr/man/cat1.
|
||||
|
||||
- Install the files: Makefile, README, de.h, de.c, de_stdin.c,
|
||||
de_stdout.c, de_diskio.c and de_recover.c in commands/de.
|
||||
Add -F and -T. to the Makefile, if necessary.
|
||||
|
||||
- "make" de(1). If a header file is not found, don't worry:
|
||||
You probably have it somewhere, just link it to what de(1)
|
||||
is looking for. This program also requires the subroutine
|
||||
tolower(3), see EFTH MINIX report #50, if you don't have it.
|
||||
|
||||
- Do you really want set-uid root on de?
|
||||
|
||||
- Patch the files fs/path.c, fs/link.c and fs/open.c. If
|
||||
you don't patch the file system then the recover option
|
||||
"-r" and associated commands ('x' and 'X') will not work,
|
||||
but de(1) is still functional and useful.
|
||||
|
||||
- "make" a new fs, using -DRECOVER. Rebuild a boot diskette.
|
||||
|
||||
|
||||
USING DE(1) FOR THE FIRST TIME
|
||||
|
||||
De(1) starts up in "word" mode at block 0 of the specified
|
||||
device. Hit the PGDN (or space bar) a few times, observing
|
||||
all the information on the screen. Each PGUP/PGDN moves to
|
||||
the next 1024 byte block, (de(1) only knows about 1 block per
|
||||
zone file systems). Note that "word" mode only displays 32
|
||||
bytes at a time, so you are only observing the first 32 bytes
|
||||
in the first few blocks when you skip using PGDN.
|
||||
|
||||
Now go back to block 3, (zone bit map), using "g 3 ENTER".
|
||||
Change to "map" mode "v m", and then use the down arrow key
|
||||
to check each 2 Megs in the zone bit map.
|
||||
|
||||
Now change to "block" mode using "v b". And go to some data
|
||||
block, eg. "g 1000 ENTER". Use PGUP/PGDN to see what data
|
||||
is in each nearby block.
|
||||
|
||||
Remember 'h' gives you a help page.
|
||||
|
||||
Try some more commands, for example: 'END', 'I', '/'.
|
||||
(Note: searching through a whole disk under Minix takes a
|
||||
long time: 30-60 seconds per megabyte, depending on your
|
||||
machine, drive and controller, [Minix is embarrassingly slow].)
|
||||
|
||||
Don't worry about looking at a mounted device, you must specify
|
||||
the "-w" option before the 's' command is operational, and
|
||||
this command is the only one which will try to modify the
|
||||
contents of the device.
|
||||
|
||||
|
||||
MINIX-ST
|
||||
|
||||
Please contact me if you are interesting in attempting a port
|
||||
to MINIX-ST.
|
||||
BIN
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de.c.gz
Normal file
BIN
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de.c.gz
Normal file
Binary file not shown.
323
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de.h
Normal file
323
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de.h
Normal file
@@ -0,0 +1,323 @@
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* de.h */
|
||||
/* */
|
||||
/* Definitions for the "Disk editor". */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
/* origination 1989-Jan-15 Terrence W. Holm */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* de(1) */
|
||||
/* */
|
||||
/* This is the MINIX disk editor. It allows the user to */
|
||||
/* observe and modify a file system. It can also be used */
|
||||
/* to recover unlink(2)'ed files */
|
||||
/* */
|
||||
/* See the de(1) man page. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* de Copyright Terrence W. Holm 1989 */
|
||||
/* */
|
||||
/* This program was written for users of the Minix operating */
|
||||
/* system, and in the spirit of other public domain software */
|
||||
/* written for said system, this source code is made available */
|
||||
/* at no cost to everyone. I assume no responsibility for */
|
||||
/* damage to file systems caused by this program. */
|
||||
/* */
|
||||
/* This program (one .h, five .c's and a "man" page) may be */
|
||||
/* copied and/or modified subject to (1) no charge must be */
|
||||
/* made for distribution, other than for the medium, (2) all */
|
||||
/* modified sources must be clearly marked as such, (3) all */
|
||||
/* sources must carry this copyright. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* files */
|
||||
/* */
|
||||
/* de.h Definitions */
|
||||
/* de.c The main loop */
|
||||
/* de_stdin.c Character input routines */
|
||||
/* de_stdout.c Output routines */
|
||||
/* de_diskio.c File system read/write */
|
||||
/* de_recover.c File restoration routines */
|
||||
/* */
|
||||
/* de.1 "Man" page */
|
||||
/* Makefile For "make" */
|
||||
/* README Installation help */
|
||||
/* */
|
||||
/* */
|
||||
/* fs/path.c was modified to support the 'x' command. */
|
||||
/* fs/link.c and fs/open.c were changed for 'X'. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
/* General constants */
|
||||
|
||||
#define MAX_STRING 60 /* For all input lines */
|
||||
#define MAX_PREV 8 /* For 'p' command */
|
||||
#define SEARCH_BUFFER (4*K) /* For '/' and 'n' */
|
||||
|
||||
|
||||
/* Files */
|
||||
|
||||
#define TMP "/tmp" /* For "-r" output */
|
||||
#define DEV "/dev" /* Where devices are */
|
||||
|
||||
|
||||
/* a.out header constants (see a.out.h, if you have it) */
|
||||
|
||||
#if (CHIP == INTEL)
|
||||
#define A_OUT 0x0301
|
||||
#define SPLIT 0x0420
|
||||
#endif
|
||||
|
||||
#if (CHIP == M68000)
|
||||
#define A_OUT 0x0301
|
||||
#define SPLIT 0x0B20
|
||||
#endif
|
||||
|
||||
|
||||
/* Each buffer is 1k. In WORD mode 16 words (32 bytes) can be */
|
||||
/* displayed at once. In BLOCK mode 1K bytes can be displayed. */
|
||||
/* In MAP mode 2048 bits (256 bytes) are displayed. */
|
||||
|
||||
#define K 1024 /* STD_BLK */
|
||||
#define K_MASK (~(K-1)) /* Round to K boundary */
|
||||
#define K_SHIFT 10 /* Ie. 1<<10 = K */
|
||||
#define PAGE_MASK 0x1f /* Word mode: 32 bytes */
|
||||
#define PAGE_SHIFT 5 /* Ie. 1<<5 = 32 */
|
||||
#define MAP_BITS_PER_BLOCK (8 * K) /* 1k block, 8192 bits */
|
||||
#define MAP_MASK 0xff /* 256 bytes/screen */
|
||||
|
||||
|
||||
|
||||
/* Terminal i/o codes */
|
||||
|
||||
#define CTRL_D '\004' /* ASCII ^D */
|
||||
#define BELL '\007' /* ASCII bell code */
|
||||
#define BS '\010' /* ASCII back space */
|
||||
#define CTRL_U '\025' /* ASCII ^U */
|
||||
#define ESCAPE '\033' /* ASCII escape code */
|
||||
#define DEL '\177' /* ASCII delete code */
|
||||
|
||||
|
||||
/* Input escape codes generated by the Minix console. */
|
||||
/* Format: ESC [ X. */
|
||||
|
||||
#define ESC_HOME ('H' + 0x80)
|
||||
#define ESC_UP ('A' + 0x80)
|
||||
#define ESC_PGUP ('V' + 0x80)
|
||||
#define ESC_LEFT ('D' + 0x80)
|
||||
#define ESC_5 ('G' + 0x80)
|
||||
#define ESC_RIGHT ('C' + 0x80)
|
||||
#define ESC_END ('Y' + 0x80)
|
||||
#define ESC_DOWN ('B' + 0x80)
|
||||
#define ESC_PGDN ('U' + 0x80)
|
||||
#define ESC_PLUS ('T' + 0x80)
|
||||
#define ESC_MINUS ('S' + 0x80)
|
||||
|
||||
|
||||
/* Graphic box codes - only applicable for console display */
|
||||
/* in visual mode "map". */
|
||||
|
||||
#if (CHIP == INTEL)
|
||||
#define BOX_CLR ' ' /* Empty box */
|
||||
#define BOX_ALL '\333' /* Filled box */
|
||||
#define BOX_TOP '\337' /* Filled upper half */
|
||||
#define BOX_BOT '\334' /* Filled lower half */
|
||||
#endif
|
||||
|
||||
#if (CHIP == M68000)
|
||||
/* Please change these. */
|
||||
#define BOX_CLR ' ' /* Empty box */
|
||||
#define BOX_ALL '=' /* Filled box */
|
||||
#define BOX_TOP '-' /* Filled upper half */
|
||||
#define BOX_BOT '_' /* Filled lower half */
|
||||
#endif
|
||||
|
||||
|
||||
/* Move positions for the output display. */
|
||||
|
||||
#define STATUS_COLUMN 2
|
||||
#define STATUS_LINE 0
|
||||
#define BLOCK_COLUMN 4
|
||||
#define BLOCK_LINE 4
|
||||
#define INFO_COLUMN 30
|
||||
#define INFO_LINE BLOCK_LINE
|
||||
#define PROMPT_COLUMN 0
|
||||
#define PROMPT_LINE 23
|
||||
#define WARNING_COLUMN 10
|
||||
#define WARNING_LINE 10
|
||||
|
||||
|
||||
|
||||
/* Values returned by Process() and Get_Filename() */
|
||||
|
||||
#define OK 0 /* No update required */
|
||||
#define REDRAW 1 /* Redraw whole screen */
|
||||
#define REDRAW_POINTERS 2 /* Redraw just ptrs */
|
||||
#define ERROR 3 /* Beep */
|
||||
|
||||
|
||||
/* Visual modes */
|
||||
|
||||
#define WORD 1
|
||||
#define BLOCK 2
|
||||
#define MAP 3
|
||||
|
||||
|
||||
typedef struct de_state /* State of disk ed. */
|
||||
{
|
||||
/* Information from super block */
|
||||
|
||||
unsigned inodes; /* Number of i-nodes */
|
||||
unsigned zones; /* Total # of blocks */
|
||||
unsigned inode_maps; /* I-node map blocks */
|
||||
unsigned zone_maps; /* Zone map blocks */
|
||||
unsigned inode_blocks; /* I-node blocks */
|
||||
unsigned first_data; /* Total non-data blks */
|
||||
|
||||
unsigned inodes_in_map; /* Bits in i-node map */
|
||||
unsigned zones_in_map; /* Bits in zone map */
|
||||
|
||||
/* Information from map blocks */
|
||||
|
||||
char inode_map[ I_MAP_SLOTS * K ];
|
||||
char zone_map[ ZMAP_SLOTS * K ];
|
||||
|
||||
/* Information for current block */
|
||||
|
||||
off_t address; /* Current address */
|
||||
off_t last_addr; /* For erasing ptrs */
|
||||
unsigned block; /* Current block (1K) */
|
||||
unsigned offset; /* Offset within block */
|
||||
|
||||
char buffer[ K ];
|
||||
|
||||
/* Display state */
|
||||
|
||||
int mode; /* WORD, BLOCK or MAP */
|
||||
int output_base; /* 2, 8, 10, or 16 */
|
||||
|
||||
/* Search information */
|
||||
|
||||
char search_string[ MAX_STRING + 1 ]; /* For '/' and 'n' */
|
||||
off_t prev_addr[ MAX_PREV ]; /* For 'p' command */
|
||||
int prev_mode[ MAX_PREV ];
|
||||
|
||||
/* File information */
|
||||
|
||||
char *device_name; /* From command line */
|
||||
int device_d;
|
||||
int device_mode; /* O_RDONLY or O_RDWR */
|
||||
unsigned device_size; /* Number of blocks */
|
||||
|
||||
char file_name[ MAX_STRING + 1 ]; /* For 'w' and 'W' */
|
||||
FILE *file_f;
|
||||
int file_written; /* Flag if written to */
|
||||
|
||||
} de_state;
|
||||
|
||||
|
||||
|
||||
/* Forward references for external routines */
|
||||
|
||||
/* libc.a */
|
||||
|
||||
struct passwd *getpwuid();
|
||||
struct group *getgrgid();
|
||||
char *ctime();
|
||||
char *getenv();
|
||||
char *tgetstr();
|
||||
char *tgoto();
|
||||
char *ttyname();
|
||||
FILE *fopen();
|
||||
off_t lseek();
|
||||
|
||||
|
||||
/* de.c */
|
||||
|
||||
void main();
|
||||
int Process();
|
||||
|
||||
void Push();
|
||||
int Get_Filename();
|
||||
int Get_Count();
|
||||
int Str_Int();
|
||||
int In_Use();
|
||||
ino_t Find_Inode();
|
||||
void Exec_Shell();
|
||||
void Sigint();
|
||||
void Error();
|
||||
|
||||
|
||||
/* de_stdin.c */
|
||||
|
||||
void Save_Term();
|
||||
void Set_Term();
|
||||
void Reset_Term();
|
||||
int Get_Char();
|
||||
char *Get_Line();
|
||||
int Arrow_Esc();
|
||||
|
||||
|
||||
/* de_stdout.c */
|
||||
|
||||
int Init_Termcap();
|
||||
void Goto();
|
||||
void Draw_Help_Screen();
|
||||
void Wait_For_Key();
|
||||
void Draw_Prompt();
|
||||
void Erase_Prompt();
|
||||
|
||||
void Draw_Screen();
|
||||
void Draw_Strings();
|
||||
void Block_Type();
|
||||
void Draw_Words();
|
||||
void Draw_Info();
|
||||
void Draw_Block();
|
||||
void Draw_Map();
|
||||
|
||||
void Draw_Pointers();
|
||||
void Draw_Offset();
|
||||
void Word_Pointers();
|
||||
void Block_Pointers();
|
||||
void Map_Pointers();
|
||||
|
||||
void Print_Number();
|
||||
void Print_Ascii();
|
||||
void Warning();
|
||||
|
||||
|
||||
/* de_diskio.c */
|
||||
|
||||
void Read_Disk();
|
||||
void Read_Block();
|
||||
void Read_Super_Block();
|
||||
void Read_Bit_Maps();
|
||||
off_t Search();
|
||||
void Write_Word();
|
||||
|
||||
|
||||
/* de_recover.c */
|
||||
|
||||
int Path_Dir_File();
|
||||
char *File_Device();
|
||||
ino_t Find_Deleted_Entry();
|
||||
off_t Recover_Blocks();
|
||||
|
||||
|
||||
#undef printf /* Because fs/const.h */
|
||||
/* defines it. */
|
||||
326
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de_diskio.c
Normal file
326
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de_diskio.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* de_diskio.c */
|
||||
/* */
|
||||
/* Reading and writing to a file system device. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
/* origination 1989-Jan-15 Terrence W. Holm */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
#include <minix/config.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <minix/const.h>
|
||||
#include <minix/type.h>
|
||||
#include "../../fs/const.h"
|
||||
#include "../../fs/type.h"
|
||||
#include "../../fs/super.h"
|
||||
|
||||
#include "de.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Read_Disk( state, block_addr, buffer ) */
|
||||
/* */
|
||||
/* Reads a 1k block at "block_addr" into "buffer". */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
void Read_Disk( s, block_addr, buffer )
|
||||
de_state *s;
|
||||
off_t block_addr;
|
||||
char *buffer;
|
||||
|
||||
{
|
||||
if ( lseek( s->device_d, block_addr, SEEK_SET ) == -1 )
|
||||
Error( "Error seeking %s", s->device_name );
|
||||
|
||||
if ( read( s->device_d, buffer, K ) != K )
|
||||
Error( "Error reading %s", s->device_name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Read_Block( state, buffer ) */
|
||||
/* */
|
||||
/* Reads a 1k block from "state->address" into */
|
||||
/* "buffer". Checks "address", and updates */
|
||||
/* "block" and "offset". */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
void Read_Block( s, buffer )
|
||||
de_state *s;
|
||||
char *buffer;
|
||||
|
||||
{
|
||||
off_t end_addr = (long) s->device_size * K - 1;
|
||||
off_t block_addr;
|
||||
|
||||
if ( s->address < 0 )
|
||||
s->address = 0L;
|
||||
|
||||
if ( s->address > end_addr )
|
||||
s->address = end_addr;
|
||||
|
||||
/* The address must be rounded off for */
|
||||
/* certain visual display modes. */
|
||||
|
||||
if ( s->mode == WORD )
|
||||
s->address &= ~1L;
|
||||
else if ( s->mode == MAP )
|
||||
s->address &= ~3L;
|
||||
|
||||
|
||||
block_addr = s->address & K_MASK;
|
||||
|
||||
s->block = (unsigned) (block_addr >> K_SHIFT);
|
||||
s->offset = (unsigned) (s->address - block_addr);
|
||||
|
||||
Read_Disk( s, block_addr, buffer );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Read_Super_Block( state ) */
|
||||
/* */
|
||||
/* Read and check the super block. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
void Read_Super_Block( s )
|
||||
de_state *s;
|
||||
|
||||
{
|
||||
struct super_block *super = (struct super_block *) s->buffer;
|
||||
|
||||
Read_Disk( s, (long) 1 * K, s->buffer );
|
||||
|
||||
s->inodes = super->s_ninodes;
|
||||
s->zones = super->s_nzones;
|
||||
|
||||
s->inode_maps = bitmapsize(1 + s->inodes);
|
||||
s->zone_maps = bitmapsize(s->zones);
|
||||
|
||||
s->inode_blocks = (s->inodes + INODES_PER_BLOCK - 1) / INODES_PER_BLOCK;
|
||||
s->first_data = 2 + s->inode_maps + s->zone_maps + s->inode_blocks;
|
||||
|
||||
s->inodes_in_map = s->inodes + 1;
|
||||
s->zones_in_map = s->zones + 1 - s->first_data;
|
||||
|
||||
/*
|
||||
if ( s->zones != s->device_size )
|
||||
Warning( "Zone count does not equal device size" );
|
||||
*/
|
||||
|
||||
s->device_size = s->zones;
|
||||
|
||||
if ( s->inode_maps != super->s_imap_blocks )
|
||||
Warning( "Corrupted inode map count in super block" );
|
||||
|
||||
if ( s->zone_maps != super->s_zmap_blocks )
|
||||
Warning( "Corrupted zone map count in super block" );
|
||||
|
||||
if ( s->first_data != super->s_firstdatazone )
|
||||
Warning( "Corrupted first data zone count in super block" );
|
||||
|
||||
if ( super->s_log_zone_size != 0 )
|
||||
Warning( "Can not handle multiple blocks per zone" );
|
||||
|
||||
if ( super->s_magic != SUPER_MAGIC )
|
||||
Warning( "Corrupted magic number in super block" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Read_Bit_Maps( state ) */
|
||||
/* */
|
||||
/* Read in the i-node and zone bit maps from the */
|
||||
/* specified file system device. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
void Read_Bit_Maps( s )
|
||||
de_state *s;
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( s->inode_maps > I_MAP_SLOTS || s->zone_maps > ZMAP_SLOTS )
|
||||
{
|
||||
Warning( "Super block specifies too many bit map blocks" );
|
||||
return;
|
||||
}
|
||||
|
||||
for ( i = 0; i < s->inode_maps; ++i )
|
||||
{
|
||||
Read_Disk( s, (long) (2 + i) * K, &s->inode_map[ i * K ] );
|
||||
}
|
||||
|
||||
for ( i = 0; i < s->zone_maps; ++i )
|
||||
{
|
||||
Read_Disk( s, (long) (2 + s->inode_maps + i) * K, &s->zone_map[ i * K ] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Search( state, string ) */
|
||||
/* */
|
||||
/* Search from the current address for the ASCII */
|
||||
/* "string" on the device. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
off_t Search( s, string )
|
||||
de_state *s;
|
||||
char *string;
|
||||
|
||||
{
|
||||
off_t address = s->address + 1;
|
||||
off_t last_addr = address;
|
||||
char buffer[ SEARCH_BUFFER ];
|
||||
int offset;
|
||||
int tail_length = strlen( string ) - 1;
|
||||
int count = SEARCH_BUFFER;
|
||||
int last_offset;
|
||||
|
||||
|
||||
for ( ; count == SEARCH_BUFFER; address += SEARCH_BUFFER - tail_length )
|
||||
{
|
||||
if ( lseek( s->device_d, address, SEEK_SET ) == -1 )
|
||||
Error( "Error seeking %s", s->device_name );
|
||||
|
||||
if ( (count = read( s->device_d, buffer, SEARCH_BUFFER)) == -1 )
|
||||
Error( "Error reading %s", s->device_name );
|
||||
|
||||
|
||||
if ( address - last_addr >= 500L * K )
|
||||
{
|
||||
putchar( '.' );
|
||||
fflush( stdout );
|
||||
|
||||
last_addr += 500L * K;
|
||||
}
|
||||
|
||||
|
||||
last_offset = count - tail_length;
|
||||
|
||||
for ( offset = 0; offset < last_offset; ++offset )
|
||||
{
|
||||
register char c = buffer[ offset ];
|
||||
|
||||
if ( c == *string )
|
||||
{
|
||||
char *tail_buffer = &buffer[ offset + 1 ];
|
||||
char *tail_string = string + 1;
|
||||
|
||||
do
|
||||
{
|
||||
if ( *tail_string == '\0' )
|
||||
return( address + offset );
|
||||
}
|
||||
while ( *tail_buffer++ == *tail_string++ );
|
||||
}
|
||||
} /* end for ( offset ) */
|
||||
} /* end for ( address ) */
|
||||
|
||||
return( -1L );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Write_Word( state, word ) */
|
||||
/* */
|
||||
/* Write a word at address. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
void Write_Word( s, word )
|
||||
de_state *s;
|
||||
unsigned word;
|
||||
|
||||
{
|
||||
if ( s->address & 01 )
|
||||
Error( "Internal fault (unaligned address)" );
|
||||
|
||||
if ( lseek( s->device_d, s->address, SEEK_SET ) == -1 )
|
||||
Error( "Error seeking %s", s->device_name );
|
||||
|
||||
if ( write( s->device_d, (char *) &word, 2 ) != 2 )
|
||||
Error( "Error writing %s", s->device_name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* The next routine is copied from fsck.c and mkfs.c... (Re)define some
|
||||
* things for consistency. This sharing should be done better in a library
|
||||
* library routine. In the library routine, the shifts should be replaced
|
||||
* by multiplications and divisions by MAP_BITS_PER_BLOCK since log2 of
|
||||
* this is too painful to get right.
|
||||
*/
|
||||
#define BITMAPSHIFT 13 /* = log2(MAP_BITS_PER_BLOCK) */
|
||||
#define bit_nr unsigned
|
||||
|
||||
/* Convert from bit count to a block count. The usual expression
|
||||
*
|
||||
* (nr_bits + (1 << BITMAPSHIFT) - 1) >> BITMAPSHIFT
|
||||
*
|
||||
* doesn't work because of overflow.
|
||||
*
|
||||
* Other overflow bugs, such as the expression for N_ILIST overflowing when
|
||||
* s_inodes is just over INODES_PER_BLOCK less than the maximum+1, are not
|
||||
* fixed yet, because that number of inodes is silly.
|
||||
*/
|
||||
int bitmapsize(nr_bits)
|
||||
bit_nr nr_bits;
|
||||
{
|
||||
int nr_blocks;
|
||||
|
||||
nr_blocks = nr_bits >> BITMAPSHIFT;
|
||||
if ((nr_blocks << BITMAPSHIFT) < nr_bits)
|
||||
++nr_blocks;
|
||||
return(nr_blocks);
|
||||
}
|
||||
589
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de_recover.c
Normal file
589
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de_recover.c
Normal file
@@ -0,0 +1,589 @@
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* de_recover.c */
|
||||
/* */
|
||||
/* File restoration routines. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
/* origination 1989-Jan-21 Terrence W. Holm */
|
||||
/* handle "holes" 1989-Jan-28 Terrence W. Holm */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
#include <minix/config.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <minix/type.h>
|
||||
#include <blocksize.h>
|
||||
#include "../../fs/const.h"
|
||||
#include "../../fs/type.h"
|
||||
|
||||
#include "de.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Path_Dir_File( path_name, dir_name, file_name ) */
|
||||
/* */
|
||||
/* Split "path_name" into a directory name and */
|
||||
/* a file name. */
|
||||
/* */
|
||||
/* Zero is returned on error conditions. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
int Path_Dir_File( path_name, dir_name, file_name )
|
||||
char *path_name;
|
||||
char **dir_name;
|
||||
char **file_name;
|
||||
|
||||
{
|
||||
char *p;
|
||||
static char directory[ MAX_STRING + 1 ];
|
||||
static char filename[ MAX_STRING + 1 ];
|
||||
|
||||
|
||||
if ( (p = strrchr( path_name, '/' )) == NULL )
|
||||
{
|
||||
strcpy( directory, "." );
|
||||
strcpy( filename, path_name );
|
||||
}
|
||||
else
|
||||
{
|
||||
*directory = '\0';
|
||||
strncat( directory, path_name, p - path_name );
|
||||
strcpy( filename, p + 1 );
|
||||
}
|
||||
|
||||
if ( *directory == '\0' )
|
||||
strcpy( directory, "/" );
|
||||
|
||||
if ( *filename == '\0' )
|
||||
{
|
||||
Warning( "A file name must follow the directory name" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
*dir_name = directory;
|
||||
*file_name = filename;
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* File_Device( file_name ) */
|
||||
/* */
|
||||
/* Return the name of the file system device */
|
||||
/* containing the file "file_name". */
|
||||
/* */
|
||||
/* This is used if the "-r" option was specified. */
|
||||
/* In this case we have only been given a file */
|
||||
/* name, and must determine which file system */
|
||||
/* device to open. */
|
||||
/* */
|
||||
/* NULL is returned on error conditions. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
|
||||
char *File_Device( file_name )
|
||||
char *file_name;
|
||||
|
||||
{
|
||||
struct stat file_stat;
|
||||
struct stat device_stat;
|
||||
int dev_d;
|
||||
struct direct entry;
|
||||
static char device_name[ DIRSIZ + 1 ];
|
||||
|
||||
|
||||
if ( access( file_name, R_OK ) != 0 )
|
||||
{
|
||||
Warning( "Can not find %s", file_name );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
|
||||
if ( stat( file_name, &file_stat ) == -1 )
|
||||
{
|
||||
Warning( "Can not stat(2) %s", file_name );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
|
||||
/* Open /dev for reading */
|
||||
|
||||
if ( (dev_d = open( DEV, O_RDONLY )) == -1 )
|
||||
{
|
||||
Warning( "Can not read %s", DEV );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
|
||||
while ( read( dev_d, (char *) &entry, sizeof(struct direct) )
|
||||
== sizeof(struct direct) )
|
||||
{
|
||||
if ( entry.d_ino == 0 )
|
||||
continue;
|
||||
|
||||
strcpy( device_name, DEV );
|
||||
strcat( device_name, "/" );
|
||||
strncat( device_name, entry.d_name, DIRSIZ );
|
||||
|
||||
if ( stat( device_name, &device_stat ) == -1 )
|
||||
continue;
|
||||
|
||||
if ( (device_stat.st_mode & S_IFMT) != S_IFBLK )
|
||||
continue;
|
||||
|
||||
if ( file_stat.st_dev == device_stat.st_rdev )
|
||||
{
|
||||
close( dev_d );
|
||||
return( device_name );
|
||||
}
|
||||
}
|
||||
|
||||
close( dev_d );
|
||||
|
||||
Warning( "The device containing file %s is not in %s", file_name, DEV );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Find_Deleted_Entry( state, path_name ) */
|
||||
/* */
|
||||
/* Split "path_name" into a directory name and */
|
||||
/* a file name. Then search the directory for */
|
||||
/* an entry that would match the deleted file */
|
||||
/* name. (Deleted entries have a zero i-node */
|
||||
/* number, but the original i-node number is */
|
||||
/* placed at the end of the file name.) */
|
||||
/* */
|
||||
/* If successful an i-node number is returned, */
|
||||
/* else zero is returned. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
ino_t Find_Deleted_Entry( s, path_name )
|
||||
de_state *s;
|
||||
char *path_name;
|
||||
|
||||
{
|
||||
char *dir_name;
|
||||
char *file_name;
|
||||
|
||||
|
||||
/* Check if the file exists */
|
||||
|
||||
if ( access( path_name, F_OK ) == 0 )
|
||||
{
|
||||
Warning( "File has not been deleted" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
/* Split the path name into a directory and a file name */
|
||||
|
||||
if ( ! Path_Dir_File( path_name, &dir_name, &file_name ) )
|
||||
return( 0 );
|
||||
|
||||
|
||||
/* Check to make sure the user has read permission on */
|
||||
/* the directory. */
|
||||
|
||||
if ( access( dir_name, R_OK ) != 0 )
|
||||
{
|
||||
Warning( "Can not find %s", dir_name );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
/* Make sure "dir_name" is really a directory. */
|
||||
{
|
||||
struct stat dir_stat;
|
||||
|
||||
if ( stat( dir_name, &dir_stat ) == -1 ||
|
||||
(dir_stat.st_mode & S_IFMT) != S_IFDIR )
|
||||
{
|
||||
Warning( "Can not find directory %s", dir_name );
|
||||
return( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Make sure the directory is on the current */
|
||||
/* file system device. */
|
||||
|
||||
if ( Find_Inode( s, dir_name ) == 0 )
|
||||
return( 0 );
|
||||
|
||||
|
||||
/* Open the directory and search for the lost file name. */
|
||||
{
|
||||
int dir_d;
|
||||
int count;
|
||||
struct direct entry;
|
||||
|
||||
if ( (dir_d = open( dir_name, O_RDONLY )) == -1 )
|
||||
{
|
||||
Warning( "Can not read directory %s", dir_name );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
while ( (count = read( dir_d, (char *) &entry, sizeof(struct direct) ))
|
||||
== sizeof(struct direct) )
|
||||
{
|
||||
if ( entry.d_ino == 0 &&
|
||||
strncmp( file_name, entry.d_name, DIRSIZ - sizeof(ino_t) ) == 0 )
|
||||
{
|
||||
ino_t inode = *( (ino_t *) &entry.d_name[ DIRSIZ - sizeof(ino_t) ] );
|
||||
|
||||
close( dir_d );
|
||||
|
||||
if ( inode < 1 || inode > s->inodes )
|
||||
{
|
||||
Warning( "Illegal i-node number" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
return( inode );
|
||||
}
|
||||
}
|
||||
|
||||
close( dir_d );
|
||||
|
||||
if ( count == 0 )
|
||||
Warning( "Can not find a deleted entry for %s", file_name );
|
||||
else
|
||||
Warning( "Problem reading directory %s", dir_name );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Recover_Blocks( state ) */
|
||||
/* */
|
||||
/* Try to recover all the blocks for the i-node */
|
||||
/* currently pointed to by "s->address". The */
|
||||
/* i-node and all of the blocks must be marked */
|
||||
/* as FREE in the bit maps. The owner of the */
|
||||
/* i-node must match the current real user name. */
|
||||
/* */
|
||||
/* "Holes" in the original file are maintained. */
|
||||
/* This allows moving sparse files from one device */
|
||||
/* to another. */
|
||||
/* */
|
||||
/* On any error -1L is returned, otherwise the */
|
||||
/* size of the recovered file is returned. */
|
||||
/* */
|
||||
/* */
|
||||
/* NOTE: Once a user has read access to a device, */
|
||||
/* there is a security hole, as we lose the */
|
||||
/* normal file system protection. For convenience, */
|
||||
/* de(1) is sometimes set-uid root, this allows */
|
||||
/* anyone to use the "-r" option. When recovering, */
|
||||
/* Recover_Blocks() can only superficially check */
|
||||
/* the validity of a request. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
off_t Recover_Blocks( s )
|
||||
de_state *s;
|
||||
|
||||
{
|
||||
d_inode *inode = (d_inode *) &s->buffer[ s->offset & ~ PAGE_MASK ];
|
||||
int node = (s->address - (s->first_data - s->inode_blocks) * K) /
|
||||
INODE_SIZE + 1;
|
||||
|
||||
|
||||
if ( s->block < s->first_data - s->inode_blocks ||
|
||||
s->block >= s->first_data )
|
||||
{
|
||||
Warning( "Not in an inode block" );
|
||||
return( -1L );
|
||||
}
|
||||
|
||||
|
||||
/* Is this a valid, but free i-node? */
|
||||
|
||||
if ( node > s->inodes )
|
||||
{
|
||||
Warning( "Not an inode" );
|
||||
return( -1L );
|
||||
}
|
||||
|
||||
if ( In_Use(node, s->inode_map) )
|
||||
{
|
||||
Warning( "I-node is in use" );
|
||||
return( -1L );
|
||||
}
|
||||
|
||||
|
||||
/* Only recover files that belonged to the real user. */
|
||||
|
||||
{
|
||||
uid_t real_uid = getuid();
|
||||
struct passwd *user = getpwuid( real_uid );
|
||||
|
||||
if ( real_uid != SU_UID && real_uid != inode->i_uid )
|
||||
{
|
||||
Warning( "I-node did not belong to user %s", user ? user->pw_name : "" );
|
||||
return( -1L );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Recover all the blocks of the file. */
|
||||
|
||||
{
|
||||
off_t file_size = inode->i_size;
|
||||
int i;
|
||||
|
||||
|
||||
/* Up to 7 block pointers are stored in the i-node. */
|
||||
|
||||
for ( i = 0; i < NR_DZONE_NUM; ++i )
|
||||
{
|
||||
if ( file_size == 0 )
|
||||
return( inode->i_size );
|
||||
|
||||
if ( ! Data_Block( s, inode->i_zone[ i ], &file_size ) )
|
||||
return( -1L );
|
||||
}
|
||||
|
||||
if ( file_size == 0 )
|
||||
return( inode->i_size );
|
||||
|
||||
|
||||
/* An indirect block can contain up to 512 more block pointers. */
|
||||
|
||||
if ( ! Indirect( s, inode->i_zone[ NR_DZONE_NUM ], &file_size, 0 ) )
|
||||
return( -1L );
|
||||
|
||||
if ( file_size == 0 )
|
||||
return( inode->i_size );
|
||||
|
||||
|
||||
/* A double indirect block can contain up to 512 indirect blocks. */
|
||||
|
||||
if ( ! Indirect( s, inode->i_zone[ NR_DZONE_NUM+1 ], &file_size, 1 ) )
|
||||
return( -1L );
|
||||
|
||||
if ( file_size == 0 )
|
||||
return( inode->i_size );
|
||||
|
||||
Error( "Internal fault (file_size != 0)" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Indirect( state, block, &file_size, double )
|
||||
*
|
||||
* Recover all the blocks pointed to by the indirect block
|
||||
* "block", up to "file_size" bytes. If "double" is true,
|
||||
* then "block" is a double-indirect block pointing to 512
|
||||
* indirect blocks.
|
||||
*
|
||||
* If a "hole" is encountered, then just seek ahead in the
|
||||
* output file.
|
||||
*/
|
||||
|
||||
|
||||
int Indirect( s, block, file_size, dblind )
|
||||
de_state *s;
|
||||
zone_nr block;
|
||||
off_t *file_size;
|
||||
int dblind;
|
||||
|
||||
{
|
||||
zone_nr indirect[ NR_INDIRECTS ];
|
||||
int i;
|
||||
|
||||
/* Check for a "hole". */
|
||||
|
||||
if ( block == NO_ZONE )
|
||||
{
|
||||
off_t skip = (off_t) NR_INDIRECTS * K;
|
||||
|
||||
if ( *file_size < skip || dblind )
|
||||
{
|
||||
Warning( "File has a hole at the end" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if ( fseek( s->file_f, skip, SEEK_CUR ) == -1 )
|
||||
{
|
||||
Warning( "Problem seeking %s", s->file_name );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
*file_size -= skip;
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
|
||||
/* Not a "hole". Recover indirect block, if not in use. */
|
||||
|
||||
if ( ! Free_Block( s, block ) )
|
||||
return( 0 );
|
||||
|
||||
|
||||
Read_Disk( s, (long) block << K_SHIFT, indirect );
|
||||
|
||||
for ( i = 0; i < NR_INDIRECTS; ++i )
|
||||
{
|
||||
if ( *file_size == 0 )
|
||||
return( 1 );
|
||||
|
||||
if ( dblind )
|
||||
{
|
||||
if ( ! Indirect( s, indirect[ i ], file_size, 0 ) )
|
||||
return( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! Data_Block( s, indirect[ i ], file_size ) )
|
||||
return( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Data_Block( state, block, &file_size )
|
||||
*
|
||||
* If "block" is free then write Min(file_size, k)
|
||||
* bytes from it onto the current output file.
|
||||
*
|
||||
* If "block" is zero, this means that a 1k "hole"
|
||||
* is in the file. The recovered file maintains
|
||||
* the reduced size by not allocating the block.
|
||||
*
|
||||
* The file size is decremented accordingly.
|
||||
*/
|
||||
|
||||
|
||||
int Data_Block( s, block, file_size )
|
||||
de_state *s;
|
||||
zone_nr block;
|
||||
off_t *file_size;
|
||||
|
||||
{
|
||||
char buffer[ K ];
|
||||
off_t block_size = *file_size > K ? K : *file_size;
|
||||
|
||||
|
||||
/* Check for a "hole". */
|
||||
|
||||
if ( block == NO_ZONE )
|
||||
{
|
||||
if ( block_size < K )
|
||||
{
|
||||
Warning( "File has a hole at the end" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if ( fseek( s->file_f, block_size, SEEK_CUR ) == -1 )
|
||||
{
|
||||
Warning( "Problem seeking %s", s->file_name );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
*file_size -= block_size;
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
|
||||
/* Block is not a "hole". Copy it to output file, if not in use. */
|
||||
|
||||
if ( ! Free_Block( s, block ) )
|
||||
return( 0 );
|
||||
|
||||
Read_Disk( s, (long) block << K_SHIFT, buffer );
|
||||
|
||||
|
||||
if ( fwrite( buffer, 1, (int) block_size, s->file_f ) != (int) block_size )
|
||||
{
|
||||
Warning( "Problem writing %s", s->file_name );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
*file_size -= block_size;
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Free_Block( state, block )
|
||||
*
|
||||
* Make sure "block" is a valid data block number, and it
|
||||
* has not been allocated to another file.
|
||||
*/
|
||||
|
||||
|
||||
int Free_Block( s, block )
|
||||
de_state *s;
|
||||
zone_nr block;
|
||||
|
||||
{
|
||||
if ( block < s->first_data || block >= s->zones )
|
||||
{
|
||||
Warning( "Illegal block number" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if ( In_Use( block - s->first_data + 1, s->zone_map ) )
|
||||
{
|
||||
Warning( "Encountered an \"in use\" data block" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
290
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de_stdin.c
Normal file
290
study/linux-travel/MINIX-1.5/1.5/Source/commands/de/de_stdin.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* de_stdin.c */
|
||||
/* */
|
||||
/* Processing input from the "de" user. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
/* origination 1989-Jan-15 Terrence W. Holm */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
#include <minix/config.h>
|
||||
#include <sys/types.h>
|
||||
#include <sgtty.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../fs/const.h"
|
||||
|
||||
#include "de.h"
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Save_Term() */
|
||||
/* */
|
||||
/* Save the current terminal characteristics. */
|
||||
/* */
|
||||
/* */
|
||||
/* Set_Term() */
|
||||
/* */
|
||||
/* Set up the terminal characteristics. */
|
||||
/* */
|
||||
/* */
|
||||
/* Reset_Term() */
|
||||
/* */
|
||||
/* Restore the terminal characteristics. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
static struct sgttyb saved_mode;
|
||||
static struct tchars saved_chars;
|
||||
void Timed_Out();
|
||||
|
||||
|
||||
void Save_Term()
|
||||
|
||||
{
|
||||
ioctl( 0, TIOCGETP, &saved_mode );
|
||||
ioctl( 0, TIOCGETC, (struct sgttyb *) &saved_chars );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Set_Term()
|
||||
|
||||
{
|
||||
struct sgttyb mode;
|
||||
struct tchars chars;
|
||||
|
||||
mode = saved_mode;
|
||||
chars = saved_chars;
|
||||
|
||||
|
||||
/* No tab expansion, no echo, don't map ^M to ^J, cbreak mode */
|
||||
|
||||
mode.sg_flags = mode.sg_flags & ~XTABS & ~ECHO & ~CRMOD | CBREAK;
|
||||
|
||||
|
||||
/* Change the interrupt character to ^C */
|
||||
|
||||
chars.t_intrc = '\003';
|
||||
|
||||
ioctl( 0, TIOCSETP, &mode );
|
||||
ioctl( 0, TIOCSETC, (struct sgttyb *) &chars );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Reset_Term()
|
||||
|
||||
{
|
||||
ioctl( 0, TIOCSETP, &saved_mode );
|
||||
ioctl( 0, TIOCSETC, (struct sgttyb *) &saved_chars );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Get_Char() */
|
||||
/* */
|
||||
/* Return the next input character. Escape */
|
||||
/* sequences are mapped to special codes. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
int Get_Char()
|
||||
{
|
||||
int c;
|
||||
static int unget_char = EOF;
|
||||
|
||||
|
||||
/* Flush the output to the screen before waiting */
|
||||
/* for input from the user. */
|
||||
|
||||
fflush( stdout );
|
||||
|
||||
if ( unget_char == EOF )
|
||||
{
|
||||
while ( (c = Timed_Get_Char( 60 * 60 )) < EOF )
|
||||
printf( "%c", BELL );
|
||||
}
|
||||
else
|
||||
{
|
||||
c = unget_char;
|
||||
unget_char = EOF;
|
||||
}
|
||||
|
||||
if ( c == EOF )
|
||||
return( EOF );
|
||||
|
||||
if ( c != ESCAPE )
|
||||
return( c );
|
||||
|
||||
if ( (c = Timed_Get_Char( 1 )) <= EOF )
|
||||
return( ESCAPE );
|
||||
|
||||
if ( c != '[' )
|
||||
{
|
||||
unget_char = c;
|
||||
return( ESCAPE );
|
||||
}
|
||||
|
||||
if ( (c = Timed_Get_Char( 1 )) <= EOF )
|
||||
{
|
||||
unget_char = '[';
|
||||
return( ESCAPE );
|
||||
}
|
||||
|
||||
return( c | 0x80 ); /* Flag ESC [ x */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int Timed_Get_Char( time )
|
||||
int time;
|
||||
|
||||
{
|
||||
char c;
|
||||
int count;
|
||||
|
||||
signal( SIGALRM, Timed_Out );
|
||||
|
||||
alarm( time );
|
||||
count = read( 0, &c, 1 );
|
||||
alarm( 0 );
|
||||
|
||||
if ( count <= 0 )
|
||||
return( EOF + count );
|
||||
|
||||
return( c & 0x7f );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Get_Line() */
|
||||
/* */
|
||||
/* Read a line from the user. Returns a pointer */
|
||||
/* to a local buffer, or NULL if DEL or a non- */
|
||||
/* ASCII character was typed. Processes ^H and */
|
||||
/* ^U. ^M terminates the input. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
char *Get_Line()
|
||||
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
static char line[ MAX_STRING + 1 ];
|
||||
|
||||
for ( i = 0; i <= MAX_STRING; ++i )
|
||||
{
|
||||
c = Get_Char();
|
||||
|
||||
if ( c == EOF || c == DEL || (c & 0x80) )
|
||||
return( NULL );
|
||||
|
||||
if ( c == BS )
|
||||
{
|
||||
if ( --i >= 0 )
|
||||
{
|
||||
printf( "\b \b" );
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( c == CTRL_U )
|
||||
{
|
||||
for ( --i; i >= 0; --i )
|
||||
printf( "\b \b" );
|
||||
}
|
||||
|
||||
else if ( c == '\r' )
|
||||
{
|
||||
line[ i ] = '\0';
|
||||
return( line );
|
||||
}
|
||||
|
||||
else if ( i < MAX_STRING )
|
||||
{
|
||||
line[ i ] = c;
|
||||
Print_Ascii( c );
|
||||
}
|
||||
|
||||
else /* Line buffer is full, don't add any more to it. */
|
||||
{
|
||||
putchar( BELL );
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
Error( "Internal fault (line buffer overflow)" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* */
|
||||
/* Arrow_Esc( char ) */
|
||||
/* */
|
||||
/* If the keyboard does not generate Ansi escape */
|
||||
/* codes for the arrow keys, but does generate */
|
||||
/* single byte control codes, then map these */
|
||||
/* codes to the special characters we are using */
|
||||
/* to denote the Ansi escape codes. */
|
||||
/* */
|
||||
/****************************************************************/
|
||||
|
||||
|
||||
extern char Kup; /* (ku) - Up arrow key */
|
||||
extern char Kdown; /* (kd) - Down arrow key */
|
||||
extern char Kleft; /* (kl) - Left arrow key */
|
||||
extern char Kright; /* (kr) - Right arrow key */
|
||||
|
||||
|
||||
int Arrow_Esc( c )
|
||||
int c;
|
||||
|
||||
{
|
||||
if ( c == Kup )
|
||||
return( ESC_UP );
|
||||
|
||||
if ( c == Kdown )
|
||||
return( ESC_DOWN );
|
||||
|
||||
if ( c == Kleft )
|
||||
return( ESC_LEFT );
|
||||
|
||||
if ( c == Kright )
|
||||
return( ESC_RIGHT );
|
||||
|
||||
return( c );
|
||||
}
|
||||
|
||||
void Timed_Out()
|
||||
{}
|
||||
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user