SCO UNIX文件卷结构分析及误删文件的恢复
* 187800 磁盘块0x627的内容没有丢失: # hd -s 0x189c00 -n 0x400 /dev/user 189c00 31 32 33 34 35 36 37 1a 00 00 00 00 00 00 00 00 1234567…… 189c10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …………… * 18a000 由于系统每次分配磁盘块给文件时,都遵循这一算法,所以当文件被删除后,我们同样可以按照这一算法推算出原本属于该文件的磁盘块号,这样我们就能完全恢复误删的文件了。
2.误删文件的恢复 根据以上SCO UNIX文件卷结构和磁盘块管理的特点,笔者编制了一恢复误删文件的程序并投入使用,挽救了许多数据。限于篇幅,这里只给出软件的构思和磁盘块分配算法函数getNextFreeBlock(long BN)的源代码。软件构思是这样的,首先在被误删文件的文件卷下,创建一新文件,不向该文件写任何数据即关闭它,然后调用系统函数stat (char* path, structstat* buf)得到该文件的i节点,再根据磁盘块分配算法在文件卷上寻找将分配的空闲块,将块号填入i节点的磁盘块地址表并把相应位图块中的标志位置0;由于SCO UNIX把已分配磁盘块中未被使用的字节全部署0,所以我们只要找到一个尾部字节全部为0的磁盘块,就可以认为它是文件的最后一个磁盘块了,由这些磁盘块的数量和最后一个磁盘块中有效字节的长度,可以算出文件的字节长度,将此长度值也填入i节点,再把该i节点写回文件卷即可。i节点的数据结构在文件中,如下: struct dinode { ushort dimode; short dinlink; ushort diuid; ushort digid; off-t disize; char diaddr[40]; /*磁盘块地址表*/ . . . }; 对于大文件的一次间址块、二次间址块和三次间址块的块号,只要稍做处理即可找到,这里不再赘述,留给读者思考。 函数getNextFreeBlock(long BN)的返回值是文件卷中下一个将要分配的空闲块的块号,失败时返回-1,表明已无空闲块可分配。输入参数是起始块号,若是分配给文件的第一块,则BN为0。源代码如下,其中BBIT存放的是文件卷位图索引块的数据。函数readABlock (longBN, void* buf)的功能是将文件卷的BN号磁盘块的内容读入缓冲区buf。 extern long BBIT[0x100]; long getNextFreeBlock(long BN) { long lg; ushort uBuf[0x200]; int i,k,m,n; if (BN>superBlock,s-fsize) return -1; sync(); for (k=BN{ readABlock(BBIT[k],uBuf); for (m=(BBIT[k]{ n=(BBIT[k]+m*0x10)>BN?0:(BN-BBIT[k]-m*0x10+1); while (n<0x10&&(uBuf[m]&(1<++n; if (n!=0x10) { lg=BBIT[k]+m*0x10+n; i=0x10-(BN-BBIT[0])%0x10; if (BN==0||lg(((lg-BBIT[0])%0x10)=0&&uBuf[m]==0xffff)) return lg; } } } return -1; } 注意,在恢复文件之后,为了使系统的内存超级块和文件卷上的超级块保持一致,对于子文件卷和根文件卷,应分别执行以下命令: # fsck -f y /dev/user # fsck -f y -b /dev/root 显然,掌握了SCO UNIX文件卷的结构特点和磁盘块的管理方式后,我们还能进行更多的应用。比如磁盘块使用情况图、文件磁盘块规整等等。由于当前涉及SCO UNIX内核设计方面的资料太少,笔者对它也只有一个初步地探索。在这里,笔者殷切地希望此篇拙作还能起一抛砖引玉之用。 | |