一、引言
在DOS系統下,在計算機應用培訓中因培訓要求不同, 對軟件的要求也不同,由於學員的誤操作,存放在硬盤上的軟件和重要數據容易被非法刪除或受到損壞。對此,筆者通過對硬盤管理的深入分析和實踐,總結出了在硬盤上備份、保護重要數據和軟件的一種新的行之有效的方法:建立多個PRI DOS 分區, 不同的培訓要求使用不同的PRI DOS分區,在使用時同時只有一個PRI DOS 分區可供使用, 其余PRI DOS分區均被隱含。
二、分區表結構
眾所周知,DOS操作系統下,一個硬盤可以分為PRI DOS分區和擴展分區兩大部分,而擴展分區中又可進一步建立多個邏輯分區。這些PRI DOS分區和邏輯分區都可象單獨的物理硬盤一樣使用。那麼DOS是怎樣實現對這些分區的管理和使用的呢?DOS 管理硬盤的秘密是兩個表:硬盤分區表鏈。系統在啟動過程中,DOS 根據硬盤分區表鏈及分區表提供的分區信息建立了各個分區的磁盤參數表(BPB表),而磁盤參數表是DOS訪問硬盤的基礎。 因此分區表鏈及分區表在硬盤存取中具有非常重要的地位。
分區表鏈存於硬盤上,一般由一個主引導結點和多個普通結點構成。主引導結點同PRI DOS分區對應,為硬盤的0柱面0頭1扇區,是硬盤主引導記錄扇區。在頭結點扇區中,從開始到0DAH的218 字節是一段主引導程序;從0DBH到1BDH共228字節為00H;從1BEH到1FDH處64字節是硬盤的主分區表,共四個表項,每個表項16字節,其中前兩個表項分別指示主分區和擴展分區在硬盤中的信息,後兩個表項一般不用,全為00H;;扇區最後兩個字節是結束標志55H、AAH。
表項的數據結構如下:
相對偏移 長度(BYTE) 含義
0 1 激活標志
1 3 分區起始位置(柱、頭、扇)
4 1 分區類型
5 3 分區終止位置(柱、頭、扇)
8 4 分區起始扇區的相對序號
12 4 分區大小
表項結構中的激活標志在激活時為80H(否則為00H),所謂起始位置,對於本分區表項而言,是該分區的起始柱1頭1扇區;對於擴展表項而言指的是相應的擴展分區的起始柱0頭1扇區。分區類型常見值有1、4、6、5等。1表示12位FAT的分區,4表示16位FAT的分區,6 表示容量大於32M的分區,5表示擴展分區。分區大小等於各相應分區從起始扇區到終止扇區的扇區數,對於本分區表項,此值不含隱含扇區,對於擴展表項此值包含隱含扇區,而對PRI DOS 分區裡的擴展表項,此值等於各邏輯分區所有扇區包括隱含扇區之和。所謂起始扇區的相對應序號,其相對起點分三種情況:對於本分區表項,序號是相對於該分區的起始柱0頭1扇區;對於擴展表項,若是PRI DOS的擴展分區,則相對於PRI DOS分區的主引導記錄扇區;若是邏輯分區的擴展, 則一律相對於整個擴展分區的起點,此起點一般就是第一邏輯分區的起始柱0頭1扇區。
三、建立多個PRI DOS分區
從上面的分析中我們清楚了分區表由四個表項組成(盡管一般最多只使用兩項),並且主分區表的第一表項指向PRI DOS分區,第二個表項指向擴展分區。如果按照正常的使用方法,完全沒有必要設置四個表項,既然如此設置,必有其使用的目的。由於主分區表中的擴展表項中的某些項包含了所有擴展分區的有關信息,為此我先用 FDISK建立只有一個邏輯分區的擴展分區。然後將該擴展分區表項的分區類型由5改為6,再將其激活標志由00H改為80H(注意必須同時將原先的PRI DOS分區的激活標志由80H改為00H)。 然後必須重新用軟盤啟動機器並格式化C盤,則就可用新建立的PRI DOS分區啟動機器( 原先的PRI DOS分區的盤符變為D)。這樣就建立了兩個PRI DOS分區。
四、隱含分區的設置和恢復
我們已經知道硬盤主引導記錄扇區中從0DBH到1BDH共228 個字節為00H,在建立了多個PRI DOS分區之後,就可利用這228 個字節的最後64個字節來保存四個表項有內容。選定一個PRI DOS分區, 然後將四個表項中的其它所有分區類型為非擴展分區的表項的內容全部改為00H。這樣在硬盤上就只有一個PRI DOS分區,其它被隱含起來。
如要將隱含分區恢復正常,只需將其保存在主硬盤主引導扇區中的內容重新寫入到該表項即可。
五、源程序
下面給出源程序:PDOS.CPP。該源程序在編譯環境TURBOC++ 3.0下在兼容機上編譯。使用方法為在DOS提示符下鍵入:[D:] [ PATH]
PDOS <C/S/R/1/2/3/4>(S:建立PRI DOS分區;S:對PRI DOS分區表項進行備份;R:收復PRI DOS分區表項;1:只保留PRI DOS分區表項的第一項,其余均隱含;2:只保留PRI DOS分區表項的第二項;3: 只保留PRI DOS分區表項的第三項;4:只保留PRI DOS分區表項的最後一項)。
以下為PDOS.CPP程序清單:
#include<dos.h>
#include<bios.h>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
struct HSC
{char hd,sc,cy;};
struct PartitionTable
{char Flag; /* 激活標志 */
HSC begin; /* 開始位置 */
char TYpe; /* 分區類型 */
HSC end; /* 結束位置 */
long id; /* 開始扇區的相對序號 */
long size; /* 分區大小 */
};
struct note /* 結點結構 */
{char boot1[366];
PartitionTable PT[1];
PartitionTable PT1[4];
PartitionTable PT2[4]; /* 主DOS分區表項 */
char f[2];
}dosboot;
void create_pri_dos(); /* 建立(將擴展分區修改成)主DOS分區 */
void set_hidde_dos(); /* 對主DOS分區表項進行備份 */
void recall_dos(); /* 恢復主DOS分區表項 */
void change_dos(char n); /* 只保留一個主DOS分區,其余均隱含 */
main(int argc,char *argv[])
{
char n;
if (argc!=2)
{ printf("Bad connamd !");
return 0;
};
strlwr(argv[1]); /* 將參數中的大寫字母轉換成小寫字母 */
while((*(argv[1]++))==0); /* 搜尋第一個非空格字符 */
n=*(--argv[1]);
switch(n){
case 'c':
create_pri_dos();
break;
case 's':
set_hidde_dos();
break;
case 'r':
recall_dos();
break;
case '1': /* 只保留主DOS分區表項中的第一項,其余主DOS分區表項均隱含 */
change_dos(n);
break;
case '2': /* 只保留主DOS分區表項中的第二項 */
change_dos(n);
break;
case '3': /* 只保留主DOS分區表項上的第三項 */
change_dos(n);
break;
case '4': /* 只保留主DOS分區表項上的第四項 */
change_dos(n);
break;
default:
return 0;
};
return 0;
}
void create_pri_dos()
{int i;
biosdisk(2,0x80,0,0,1,1,&dosboot);
for (i=0;i<4;i++)
{if ((dosboot.PT2[i].TYpe!=0)&&(dosboot.PT2[i].TYpe!=5))
{dosboot.PT2[i].Flag=0x00;};
if (dosboot.PT2[i].TYpe==5)
{dosboot.PT2[i].TYpe=6;
dosboot.PT2[i].Flag=0x80;};
};
biosdisk(3,0x80,0,0,1,1,&dosboot);
return;
};
void set_hidde_dos()
{
int i;
biosdisk(2,0x80,0,0,1,1,&dosboot);
for(i=0;i<4;i++)
{if ((dosboot.PT2[i].TYpe!=0)&&(dosboot.PT2[i].TYpe!=5))
{dosboot.PT1[i]=dosboot.PT2[i];};
};
biosdisk(3,0x80,0,0,1,1,&dosboot);
return;
};
void recall_dos()
{
int i;
biosdisk(2,0x80,0,0,1,1,&dosboot);
for (i=0;i<4;i++)
{if (dosboot.PT1[i].TYpe!='0')
{
dosboot.PT2[i]=dosboot.PT1[i];
dosboot.PT1[i]=dosboot.PT[0];
};
};
biosdisk(3,0x80,0,0,1,1,&dosboot);
return;
};
void change_dos(char n)
{
int i,m;
m=n-49;
biosdisk(2,0x80,0,0,1,1,&dosboot);
if (dosboot.PT1[m].TYpe!=0)
{ for (i=0;i<4;i++)
{if (dosboot.PT1[i].TYpe!=0)
{dosboot.PT2[i]=dosboot.PT[0];};
};
dosboot.PT2[m]=dosboot.PT1[m];
dosboot.PT2[m].Flag=0x80;
};
biosdisk(3,0x80,0,0,1,1,&dosboot);
return;
};
六、舉例及注意事項
在1.2G的硬盤上建立三個PRI DOS分區,大小分別為300Mb, 400M和500MB的例子:
首先用FDISK建立一個300MB的PRI DOS分區和400MB的擴展分區,並激活PRI DOS分區,用軟盤啟動計算機並格式化C盤,執行PDOS S命令,使擴展分區變成PRI DOS分區,再用軟盤啟動計算機並格式化C盤,原先的PRI DOS分區的盤符變為D。然後用FDISK建立500MB的擴展分區,在執行PDOS S命令後,再用軟盤啟動計算機並格式化C盤, 這樣就建立了三個PRI DOS分區。其盤符和容量的對應關系為C:500MB; D :300MB;E:400MB。
由於在PRI DOS 分區表項之間切換時只保留一個表項可供使用,因此必須將PDOS.EXE程序拷貝到所有PRI DOS分區中。另個讀者在應用本程序時一定要准確無誤地輸入源程序,以防破壞硬盤上的數據。