Linux 版 (精华区)
发信人: netiscpu (夜☆星光点点☆), 信区: Linux
标 题: 编程恢复UNIX中误删的文件
发信站: 紫 丁 香 (Sun Nov 15 21:57:46 1998), 转信
发信人: pipishi.bbs@bbs.nju.edu.cn (奔跑的小狮), 信区: program
标 题: 编程恢复UNIX中误删的文件
发信站: nju_bbs (Thu May 7 22:45:46 1998)
转信站: sjtubbs!sjtunews!ustcnews!nju_bbs
Undelete、Recycled(回收站)早已成为Dos/Windows用户熟悉的恢
复删除文件的管理工具,而在UNIX中,虽然有些版本的UNIX操作系统提
供有类似于"垃圾箱"的工具,却一直没有给用户提供恢复删除文件的
程序。在UNIX中,一不小心误删了重要文件该怎么办?早先,有不少用
户自己编制程序解决此问题,不过程序结构较复杂,而且可靠性欠佳,
一般UNIX初级用户也较难掌握。笔者针对此问题编写了一段简短的C
语言程序(UNIX中ANSIC标准),由UNIX自带的C编译器cc进行编译,在UN
IX下运行。
首先介绍一下UNIX磁盘文件系统结构。UNIX文件系统结构完全不
同于DOS/Windows系统,它给磁盘上的每个物理块一个对应的逻辑块号
。在一般不涉及物理存取的操作中只用逻辑块号,在涉及到物理存取
时,再将逻辑号转换为物理块号 。UNIX还把磁盘的文件当作磁带来看
待,一条带称为一个文件卷。每个文件都可存放一个独立的文件系统,
但不能将一个文件卷分散在多个储存质上。文件按物理块号排列如下
所示:
0# 1# 2# … m# m+1# m+2# … n-1# n#
在文件卷中,0#块一般用于系统引导或空闲,与文件系统关系不大
。1#块存放了整个文件卷的资源信息,一般称为超级块(superblock)
或专用块。从2#块起直至某一块(这里暂且定为m+1#块)止是索引节点
,称为i节点表,其中存放的是文件的描述信息,如用户标识、组标识、
文件类别、文件存取时间、文件链接个数、文件大小等。每个磁盘的
i节点大小为64字节,而每个物理块为512字节(或1024字节),因而一个
物理块可以存放8(或16)个节点。从第m+2#块到第n块,存放文件本身
。
下面我们对本程序的构思和机理作适当分析。用户在使用某个文
件时,通过该文件的路径找到该文件的目录项,再由目录中的i节点号
找到该文件的i节点,根据i节点提供的地址信息就能找到该文件中的
数据。文件被删除后,目录项中的i节点号被置成0,内部i节点加入到
空闲i节点表中,将文件占用的数据项也作为空闲块连入到空闲块表中
。但是i节点及文件所占数据块中的内容并未被破坏(未进行磁盘写操
作),这就为文件的恢复工作提供可能。
根据以上情况,当文件被删除后,又没有磁盘空间分配操作时,可
以用下述方法恢复删除文件。获取被删除文件的i节点号,按文件系统
的结构找到相应的i节点,读取它所指出的数据块信息,存入一个新文
件中 ,由此可达到恢复文件的目的。例如,在lk文件系统中,m号i节点
在文件系统中的偏移值为(2*1024)+64*(m-1),如要获取相应的i节点
信息,可以利用lseek函数将文件的读写指针移到该位置,读取64个字
节,便是i节点信息了,再利用其中的addr[40]域即可找到文件的数据
块地址。
文件被删除时,该文件的i节点号已从当前目录中删除,因此事先
必须保存i节点号,以备恢复时使用。所以,如何在文件被删除时保存i
节点号就成为一个关键问题。这里采用开辟缓冲区的方法:在文件被
删除之前将该文件的目录项内容拷贝到某一个公用的文件中,暂时存
起来。这个公用文件定义为/usr/restore,该文件的最大长度是固定
的,需恢复删除文件时就从/usr/restore文件中读取i节点号。下面是
程序清单。
/*restore.c*/
#include<stdio.h>
#include<sys/types.h>
#include<sys/ino.h>
#include<dirent.h>
#include<sys/dir.h>
main(argc,argv)
int argc;
char*argv[];
{
int no,a,fd,fdt,*ip,i,m,k,n;
char s[4],buf[1024],buft[1024],sbu[300000],*point;
struct dinode inodet;
if(argc!=3){
printf("Usage:restore oldfile newfile!\n");
exit(1);
}
if((no=getino(argv[1]))==0 {
printf("No file has been delete!\n");
exit(1);
}
if((fd=open("/dev/dsk/0s3",0))==-1 ){
printf("Can not open /dev/dsk/0s3 \n");
/* /dev/dsk/0s3为被删文件所在文件系统的设备文件名 *
/
exit(1);
}
lseek(fd,(no-1)*64+2048,0);
if((n=read(fd,&inode,64))!=64) {
printf("Error in read i-node\n");
exit(1);
}
if((fdt—creat(argv[2],0666))==-1) {
printf("Can not creat %s\n",argv[2]);
exit(1);
}
point=sbu;
k=inodet.di—size/1024;
if(k<10) {
m=0;
k++;
m=3*k;
}
else{
m=k-9;
k=30;
}
for(i=0;i<k;i++) {
s[i%3]=inodet.de—addr[i];
if(i%3==2) {
s[3]=0;
ip=(int *)s;
lseek(fd,(*ip)*1024,0);
n=read(fd,buf,1024);
strcpy(point,buf,n);
point+=n;
}
}
if(1) { /* 文件大小超过 10k*/
s[0]=inodet.di—adrr[30];
s[1]=inodet.di—adrr[31];
s[2]=inodet.di—adrr[32];
s[3]=0;
ip=(int *)s;
lseek(fd,(*ip)*1024,0);
read(fd,buft,1024);
1 *=4;
for(i=0;i<1;i++){
s[i%4]=buf1[i];
if(i%4==3)
ip=(int *)s;
lseek(fd,(*ip)*1024,0);
n=read(fd,buf,1024);
strcpy(point,buf,n);
point +=n;
} /* if */
} /* for */
}
write(fdt,sbu,inodet,di—size);
}
int getino(name)
/*函数getino从/usr/restore文件中获取误删文件的i节点号
char *name;
{
int fd,n;
struct direct buf;
fd=open("/usr/restore",0);
while((n=read(fd,&buf,sizeof(buf)))!=0) {
if(n!=16){
printf("Error in read \n");
exit(1);
}
if(strcmp(buf.d—name,name)==0) {
close(fd);
return(buf.d—ino);
}
} /*while */
close(fd);
return(0);
}
用户可以直接使用UNIX的vi编辑器进行程序编辑,然后使用UNIX
的cc编译器编译,例如# cc -o unrm restore.c,生成可执行文件unrm
。必须注意,以上程序可以恢复lk文件系统中的小型和中型文件,而且
在恢复文件时,必须处于超级用户的权限下。
本程序在AT&T System V Release 4环境下编写通过,有兴趣的用
户可以根据自己所使用的系统软硬件配置情况 ,对程序做相应的修改
,实现其功能
--
________ _____ _____ ______________ _____
___ __ \___(_)________ ___(_) __ ___/___ /_ ___(_)
__ /_/ /__ / ___ __ \__ / _____ \ __ __ \__ /
_ ____/ _ / __ /_/ /_ / ____/ / _ / / /_ /
/_/ /_/ _ .___/ /_/ /____/ /_/ /_/ /_/
/_/
m;36m※ 来源:.南大小百合信息交换站 bbs.nju.edu.cn.[FROM: hsia.nju.edu.cn]
--
Enjoy Linux!
-----It's FREE!-----
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: mtlab.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:4.442毫秒