每次編譯運行都要藉助別的工具手動操做,麻煩,本身寫個簡單的讀寫虛擬軟盤的程序,自動化完成這枯燥的工做吧。爲了和 DOS 命令配合,返回值和 DOS 要求的同樣:0 表示成功,1 表示失敗。linux
今天更新了下,一是 BootSector 調整了下,二是加了編譯時自動根據系統改用字符串比較函數和分隔符。小程序
/* FAT12.h 操做 FAT12 文件系統的鏡像文件的庫函數申明 四彩 2015-12-08 */ #ifndef _FAT12_H #define _FAT12_H #ifdef WINDOWS #define SEPARATOR '\\' // Windows 系統下的分隔符 #else #define SEPARATOR '/' // linux 系統下的分隔符 #define stricmp strcasecmp // 比較字符串(不區分大小寫) #endif //======================================================================================== /* 功能: 建立一個新的空白鏡像文件 參數表: strImgName = 鏡像文件名 返回值: 0 = 成功 1 = 未能建立文件 */ int CreateNewImg(char *strImgName); /* 功能: 複製引導扇區到鏡像 參數表: strImgName = 鏡像文件名 strFileName = 引導扇區文件名 返回值: 0 = 成功 1 = 失敗 */ int CopyBootSector2Img(char *strImgName, char *strFileName); // 文件屬性以下: #define DIRATTR_READ_ONLY 0x01 //只讀 #define DIRATTR_HIDDEN 0x02 //隱藏 #define DIRATTR_SYSTEM 0x04 //系統 //#define DIRATTR_VOLUME_ID 0x08 //卷標 //#define DIRATTR_DIRECTORY 0x10 //目錄 #define DIRATTR_ARCHIVE 0x20 //文檔 /* 功能: 向鏡像增長文件 參數表: strImgName = 鏡像文件名 strPathName = 源文件全路徑 ucFileAttr = 文件屬性 返回值: 0 = 成功 1 = 失敗 */ int AddFile2Img(char *strImgName, char *strPathName, unsigned char ucFileAttr); /* 功能: 從鏡像中刪除文件 參數表: strImgName = 鏡像文件名 strFileName = 目標文件名 返回值: 無 */ void DeleteFileFromImg(char *strImgName, char *strFileName); //**************************************************************************************** #endif
/* FAT12.c 操做 FAT12 文件系統的鏡像文件的實現部分 四彩 2015-12-06 */ #include <stdio.h> #include <string.h> #include <ctype.h> #include "FAT12.h" //======================================================================================== // FAT12 文件系統 3.5 英寸軟盤常量 #define TOTALSECTORS 2880 // 總扇區數 #define BYTESPERSECTOR 512 // 每扇區字節數 #define FIRSTOFFAT 1 // FAT 表的起始邏輯扇區號 #define FIRSTOFROOTDIR 19 // 根目錄的起始邏輯扇區號 #define FIRSTOFDATA 33 // 數據區的起始邏輯扇區號 //**************************************************************************************** //======================================================================================== // 目錄表項結構 typedef struct tag_DirectoryItem { char DIR_Name[11]; // 文件名, 8 + 3(注意:沒有字符串結尾符 0) char DIR_Attr; // 文件屬性 char DIR_Rsvd[10]; // 保留 unsigned short DIR_WrtTime; // 2 位,最後修改時間 unsigned short DIR_WrtDate; // 2 位,最後修改日期 unsigned short DIR_FstClus; // 2 位,此條目對應的開始簇號(即扇區號) unsigned int DIR_FileSize; // 4 位,文件大小 } T_DIRECTORYITEM; //**************************************************************************************** unsigned short ReadFatEntryValue(FILE *fpImg, unsigned short iEntry); void WriteFatEntryValue(FILE *fpImg, unsigned short iEntry, unsigned short nValue); void ConvertDirName2FileName(char *strDirName, char *strFileName); void ConvertFileName2DirName(char *strFileName, char *strDirName); unsigned short FindEmptyEntryInRootDirectory(FILE *fpImg); unsigned short FindEmptyEntryInFat(FILE *fpImg, unsigned short iFirstEntry); unsigned short FindFileInRootDirectory(FILE *fpImg, char *strFileName); unsigned short GetRestSectors(FILE *fpImg); void DeleteFile(FILE *fpImg, unsigned short iRootDirEntry); void AddFile(FILE *fpImg, FILE *fpFile, char *strDirName, unsigned char ucFileAttr); /* 功能: 建立一個新的空白鏡像文件 參數表: strImgName = 鏡像文件名 返回值: 0 = 成功 1 = 未能建立文件 */ int CreateNewImg(char *strImgName) { // 下面這段神同樣的數據就是 BootSector.sys 的 16 進制數而已 unsigned char BootSector[BYTESPERSECTOR] = { 0xEB,0x39,0x90,0x4E,0x41,0x53,0x4D,0x2B,0x47,0x43,0x43,0x00,0x02,0x01,0x01,0x00, 0x02,0xE0,0x00,0x40,0x0B,0xF0,0x09,0x00,0x12,0x00,0x02,0x00,0x00,0x00,0x00,0x00, 0x40,0x0B,0x00,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x00,0x54,0x65,0x73,0x74,0x58, 0x5F,0x76,0x30,0x2E,0x30,0x31,0x46,0x41,0x54,0x31,0x32,0x8C,0xC8,0x8E,0xD8,0x8E, 0xD0,0xB8,0x00,0x7C,0x89,0xC5,0x89,0xC4,0xBE,0x7F,0x7D,0xE8,0x1C,0x00,0x83,0xF8, 0x00,0x75,0x08,0xBE,0x75,0x7D,0xE8,0x06,0x01,0xEB,0xFE,0x68,0x00,0x90,0x07,0xBB, 0x00,0x10,0xE8,0x50,0x00,0xEA,0x00,0x10,0x00,0x90,0x55,0x89,0xE5,0x83,0xEC,0x04, 0x06,0x51,0x53,0x68,0xE0,0x07,0x07,0xC7,0x46,0xFE,0x13,0x00,0xC7,0x46,0xFC,0x0E, 0x00,0x8B,0x46,0xFE,0x31,0xDB,0xE8,0x97,0x00,0xB9,0x10,0x00,0xB8,0x0B,0x00,0xE8, 0xB1,0x00,0x83,0xF8,0x00,0x74,0x13,0x83,0xC3,0x20,0xE2,0xF0,0xFF,0x4E,0xFC,0x74, 0x05,0xFF,0x46,0xFE,0xEB,0xDB,0x31,0xC0,0xEB,0x04,0x26,0x8B,0x47,0x1A,0x5B,0x59, 0x07,0x89,0xEC,0x5D,0xC3,0x55,0x89,0xE5,0x53,0x50,0x53,0x50,0x83,0xC0,0x1F,0xE8, 0x5E,0x00,0x58,0xE8,0x12,0x00,0x5B,0x3D,0xF8,0x0F,0x73,0x06,0x81,0xC3,0x00,0x02, 0xEB,0xE8,0x58,0x5B,0x89,0xEC,0x5D,0xC3,0x55,0x89,0xE5,0x06,0x52,0x51,0x53,0x31, 0xD2,0xBB,0x03,0x00,0xF7,0xE3,0xBB,0x02,0x00,0xF7,0xF3,0x89,0xD1,0x31,0xD2,0xBB, 0x00,0x02,0xF7,0xF3,0x83,0xC0,0x01,0x52,0x51,0x50,0x68,0xE0,0x07,0x07,0x31,0xDB, 0xE8,0x1D,0x00,0x58,0x40,0xBB,0x00,0x02,0xE8,0x15,0x00,0x59,0x5B,0x26,0x8B,0x07, 0xE3,0x03,0xC1,0xE8,0x04,0x25,0xFF,0x0F,0x5B,0x59,0x5A,0x07,0x89,0xEC,0x5D,0xC3, 0x55,0x89,0xE5,0x52,0x51,0xB2,0x12,0xF6,0xF2,0x88,0xC5,0x88,0xC6,0x88,0xE1,0xD0, 0xED,0xFE,0xC1,0x80,0xE6,0x01,0xB8,0x01,0x02,0x30,0xD2,0xCD,0x13,0x59,0x5A,0x89, 0xEC,0x5D,0xC3,0x55,0x89,0xE5,0x56,0x51,0x53,0x89,0xC1,0xE3,0x09,0xAC,0x26,0x3A, 0x07,0x75,0x03,0x43,0xE2,0xF7,0x89,0xC8,0x5B,0x59,0x5E,0x89,0xEC,0x5D,0xC3,0x55, 0x89,0xE5,0x56,0x50,0xB4,0x0E,0xAC,0x3C,0x00,0x74,0x04,0xCD,0x10,0xEB,0xF7,0x58, 0x5E,0x89,0xEC,0x5D,0xC3,0x4E,0x6F,0x74,0x20,0x66,0x6F,0x75,0x6E,0x64,0x20,0x4C, 0x4F,0x41,0x44,0x45,0x52,0x20,0x20,0x53,0x59,0x53,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xAA, }; // FAT 表第一個字節表明存儲介質(0xF0 = 軟盤),第2、三字節表明 FAT 文件分配表標識符 char FATMSG[3] = {0xF0, 0xFF, 0xFF}; FILE *fpImg; unsigned long int i; // 新建鏡像文件 fpImg = fopen(strImgName, "wb"); if(fpImg == NULL) { //printf("Cann't create %s .\n", strImgName); return 1; } // 寫引導扇區 fwrite(BootSector, BYTESPERSECTOR, 1, fpImg); // 寫 FAT1 表信息 fwrite(FATMSG, 3, 1, fpImg); // 表頭 for(i = BYTESPERSECTOR + 3; i < 10 * BYTESPERSECTOR; i++) // 剩下填 0 fputc(0, fpImg); // 寫 FAT2 表信息 fwrite(FATMSG, 3, 1, fpImg); // 表頭 for(i = 10 * BYTESPERSECTOR + 3; i < 2880 * BYTESPERSECTOR; i++) // 後面所有填 0 fputc(0, fpImg); fclose(fpImg); return 0; } /* 功能: 複製引導扇區到鏡像 參數表: strImgName = 鏡像文件名 strFileName = 引導扇區文件名 返回值: 0 = 成功 1 = 失敗 */ int CopyBootSector2Img(char *strImgName, char *strFileName) { FILE *fpFile, *fpImg; unsigned char ucBuffer[BYTESPERSECTOR], ucTemp[2]; // 打開引導扇區文件 fpFile = fopen(strFileName, "rb"); if(fpFile == NULL) { //printf("%s does not exist.\n", strFileName); return 1; } // 檢查源文件長度,不能低於 512 字節 fseek(fpFile, 0, SEEK_END); if(ftell(fpFile) < BYTESPERSECTOR) { //printf("%s is less than %d bytes in length.\n", strFileName, BYTESPERSECTOR); fclose(fpFile); return 1; } // 檢查源文件5十、511處 2 個字節,必須是 0xAA55 fseek(fpFile, 510, SEEK_SET); fread(ucTemp, 2, 1, fpFile); if(ucTemp[0] != 0x55 || ucTemp[1] != 0xAA) { //printf("The last two bytes of %s are not 0xAA55!\n", strFileName); fclose(fpFile); return 1; } // 打開鏡像文件 fpImg = fopen(strImgName, "rb+"); if(fpImg == NULL) { //printf("%s does not exist.\n", strImgName); fclose(fpFile); return 1; } // 讀源文件數據到內存 fseek(fpFile, 0, SEEK_SET); fread(ucBuffer, BYTESPERSECTOR, 1, fpFile); // 寫內存數據到鏡像文件 fseek(fpImg, 0, SEEK_SET); fwrite(ucBuffer, BYTESPERSECTOR, 1, fpImg); fclose(fpFile); fclose(fpImg); return 0; } /* 功能: 向鏡像增長文件 參數表: strImgName = 鏡像文件名 strPathName = 源文件全路徑 ucFileAttr = 文件屬性 返回值: 0 = 成功 1 = 失敗 */ int AddFile2Img(char *strImgName, char *strPathName, unsigned char ucFileAttr) { FILE *fpFile, *fpImg; unsigned short iPos, iRootDirItem, size = sizeof(T_DIRECTORYITEM); T_DIRECTORYITEM tDirItem; char strDirName[12], *strFileName; // 打開兩個文件 fpFile = fopen(strPathName, "rb"); if(fpFile == NULL) { //printf("Cann't open %s .\n", strPathName); return 1; } fpImg = fopen(strImgName, "rb+"); if(fpImg == NULL) { //printf("Cann't open %s .\n", strImgName); fclose(fpFile); return 1; } // 從源文件路徑中取出文件名 strFileName = strrchr(strPathName, SEPARATOR); strFileName = ((NULL == strFileName) ? strPathName : (strFileName + 1)); // 若已存在同名文件,取得其長度 iRootDirItem = FindFileInRootDirectory(fpImg, strFileName); if(iRootDirItem < 0xFF8) { fseek(fpImg, FIRSTOFROOTDIR * BYTESPERSECTOR + iRootDirItem * size, SEEK_SET); fread(&tDirItem, size, 1, fpImg); } else tDirItem.DIR_FileSize = 0; // 判斷剩餘空間(包括已存在同名文件佔用的部分)是否足夠 fseek(fpFile, 0, SEEK_END); if((tDirItem.DIR_FileSize + GetRestSectors(fpImg) * BYTESPERSECTOR) < ftell(fpFile)) { //printf("Not enough space.\n"); fclose(fpFile); fclose(fpImg); return 1; } // 確認根目錄區是否有空表項 if(FindEmptyEntryInRootDirectory(fpImg) > 0xFF8) { //printf("Not empty item in Root Directory.\n"); fclose(fpFile); fclose(fpImg); return 1; } // 刪掉已存在的同名文件 if(iRootDirItem < 0xFF8) DeleteFile(fpImg, iRootDirItem); // 轉換文件名格式 ConvertFileName2DirName(strFileName, strDirName); // 向鏡像中增長文件 AddFile(fpImg, fpFile, strDirName, ucFileAttr); fclose(fpFile); fclose(fpImg); return 0; } /* 功能: 從鏡像中刪除文件 參數表: strImgName = 鏡像文件名 strFileName = 目標文件名 返回值: 無 */ void DeleteFileFromImg(char *strImgName, char *strFileName) { FILE *fpImg; unsigned short iEntry; fpImg = fopen(strImgName, "rb+"); if(fpImg != NULL) { iEntry = FindFileInRootDirectory(fpImg, strFileName); if(iEntry < 0xFF8) DeleteFile(fpImg, iEntry); fclose(fpImg); } } /* 功能: 讀取 FAT 表中某表項序號的值 參數表: fpImg = 鏡像文件句柄 iEntry = FAT 表項序號 返回值: FAT 表項的值 */ unsigned short ReadFatEntryValue(FILE *fpImg, unsigned short iEntry) { unsigned short nTemp; // 讀出兩個字節 fseek(fpImg, FIRSTOFFAT * BYTESPERSECTOR + iEntry * 3 / 2, SEEK_SET); fread(&nTemp, 2, 1, fpImg); // 偶數項取低 12 位,奇數項取高 12 位 return (iEntry % 2 == 0 ? nTemp & 0xFFF : nTemp >> 4); } /* 功能: 寫入 FAT 表中某表項序號的值 參數表: fpImg = 鏡像文件句柄 iEntry = FAT 表項序號 nValue = FAT 表項的值 返回值: 無 */ void WriteFatEntryValue(FILE *fpImg, unsigned short iEntry, unsigned short nValue) { unsigned short nTemp; // 讀出原位置兩個字節 fseek(fpImg, FIRSTOFFAT * BYTESPERSECTOR + iEntry * 3 / 2, SEEK_SET); fread(&nTemp, 2, 1, fpImg); // 偶數項放在低 12 位,奇數項放在高 12 位 if(iEntry % 2 == 0) nValue |= (nTemp & 0b1111000000000000); else nValue = ((nValue << 4) | (nTemp & 0b1111)); // 回寫 FAT1 fseek(fpImg, FIRSTOFFAT * BYTESPERSECTOR + iEntry * 3 / 2, SEEK_SET); fwrite(&nValue, 2, 1, fpImg); // 回寫 FAT2 fseek(fpImg, (FIRSTOFFAT + FIRSTOFROOTDIR) * BYTESPERSECTOR / 2 + iEntry * 3 / 2, SEEK_SET); fwrite(&nValue, 2, 1, fpImg); } /* 功能:將文件名從 8 + 3 大寫格式轉換爲普通字符串 參數表: strDirName = 待處理的文件名字符串,8 + 3 + 0 大寫,長 12 字符 strFileName = 處理後的文件名字符串,8 + '.' + 3 + 0,長 13 字符 返回值: 無 */ void ConvertDirName2FileName(char *strDirName, char *strFileName) { int i, j = 7, k = 10; // 前面 8 字節爲文件名 while(strDirName[j] == ' ') // 忽略掉尾部空格 j--; for(i = 0; i <= j; i++) strFileName[i] = strDirName[i]; // 後面 3 字節爲擴展名 while(strDirName[k] == ' ') k--; if(k > 7) // k < 8 則沒有擴展名 { strFileName[++j] = '.'; for(i = 8; i <= k; i++) strFileName[++j] = strDirName[i]; } // 字符串結尾符 strFileName[++j] = 0; // 將全部字符所有轉換爲小寫字符 for(i = 0; i < j; i++) strFileName[i] = tolower(strFileName[i]); } /* 功能:將文件名從普通字符串轉換爲 8 + 3 大寫格式 參數表: strFileName = 待處理的文件名字符串,8 + '.' + 3 + 0,長 13 字符 strDirName = 處理後的文件名字符串,8 + 3 + 0 大寫,長 12 字符 返回值: 無 */ void ConvertFileName2DirName(char *strFileName, char *strDirName) { int i, j = -1; char *pExtension; // 取最後一個 '.' 位置,輸入字串最多 12 個字符:8 + '.' + 3 pExtension = strrchr(strFileName, '.'); // 沒有找到 '.' 表示該文件沒有擴展名 if(NULL == pExtension) { // 文件名最長 8 字節 for(i = 0; i < 8; i++) { if(strFileName[i] == 0) break; strDirName[i] = strFileName[i]; } // 後面所有補空格 while(i < 11) strDirName[i++] = ' '; } else { // '.' 以前爲文件名,最長 8 字節 j = pExtension - strFileName; for(i = 0; i < j && i < 8; i++) strDirName[i] = strFileName[i]; // 不夠 8 字節的補空格 while(i < 8) strDirName[i++] = ' '; j++; // j + 1 跳過 '.' // '.' 以後的爲擴展名,最多 3 字節 for(i = 8; i < 11; i++, j++) { if(strFileName[j] == 0) break; strDirName[i] = strFileName[j]; } // 不夠 3 字節的補空格 while(i < 11) strDirName[i++] = ' '; } // 將全部字符所有轉換爲大寫字符 for(i = 0; i < 11; i++) strDirName[i] = toupper(strDirName[i]); // 字符串結尾符 strDirName[11] = 0; } /* 功能: 在根目錄區中尋找空值表項 參數表: fpImg = 鏡像文件句柄 返回值: 第一個空值表項序號,0xFFF = 沒有 */ unsigned short FindEmptyEntryInRootDirectory(FILE *fpImg) { T_DIRECTORYITEM tDirItem; unsigned short i, max, size = sizeof(T_DIRECTORYITEM); unsigned char ch; max = (FIRSTOFDATA - FIRSTOFROOTDIR) * BYTESPERSECTOR / size; for(i = 0; i < max; i++) { fseek(fpImg, FIRSTOFROOTDIR * BYTESPERSECTOR + i * size, SEEK_SET); fread(&tDirItem, size, 1, fpImg); // 文件名第一個字母 = 0 表示空,= 0xE5 表示已刪除的文件 ch = tDirItem.DIR_Name[0]; if((ch == 0) || (ch == 0xE5)) return i; } return 0xFFF; } /* 功能: 在 FAT 表中尋找空值表項(即尋找空扇區) 參數表: fpImg = 鏡像文件句柄 iFirstEntry = 起始表項序號 返回值: iFirstEntry 以後(包括 iStartNum)的第一個空值表項序號,0xFFF = 沒有 */ unsigned short FindEmptyEntryInFat(FILE *fpImg, unsigned short iFirstEntry) { unsigned short i, max; // 從第 iFirstEntry 號開始取值判斷到最後( / 3 = / 2 * 8 / 12) max = (FIRSTOFROOTDIR - FIRSTOFFAT) * BYTESPERSECTOR / 3; for(i = iFirstEntry; i < max; i++) { if(ReadFatEntryValue(fpImg, i) == 0) return i; } return 0xFFF; } /* 功能: 統計剩餘空間(數據區的空白扇區數) 參數表: fpImg = 鏡像文件句柄 返回值: 數據區的空白扇區數 */ unsigned short GetRestSectors(FILE *fpImg) { unsigned short iFirstEntry = 2, iNext, nNum = 0; while((iNext = FindEmptyEntryInFat(fpImg, iFirstEntry)) > 0 && (iNext < 0xFFF)) { iFirstEntry = iNext + 1; nNum++; } return nNum; } /* 功能: 在根目錄區中尋找文件 參數表: fpImg = 鏡像文件句柄 strFileName = 文件名 返回值: 該文件的表項序號,0xFFF = 未找到 */ unsigned short FindFileInRootDirectory(FILE *fpImg, char *strFileName) { T_DIRECTORYITEM tDirItem; char FileItemName[12], DirItemName[12]; unsigned short i, max, size = sizeof(T_DIRECTORYITEM); ConvertFileName2DirName(strFileName, FileItemName); DirItemName[11] = 0; max = (FIRSTOFDATA - FIRSTOFROOTDIR) * BYTESPERSECTOR / size; for(i = 0; i < max; i++) { fseek(fpImg, FIRSTOFROOTDIR * BYTESPERSECTOR + i * size, SEEK_SET); fread(&tDirItem, size, 1, fpImg); // 根據文件名判斷(FAT12 目錄結構中文件名沒有以 0 結尾,要本身控制複製長度) strncpy(DirItemName, tDirItem.DIR_Name, 11); if(!strcmp(DirItemName, FileItemName)) return i; } return 0xFFF; } /* 功能: 從鏡像中刪除文件 參數表: fpImg = 鏡像文件句柄 iEntry = 目標文件在根目錄區的表項號 返回值: */ void DeleteFile(FILE *fpImg, unsigned short iRootDirEntry) { unsigned short nFatValue, iFatNext, size = sizeof(T_DIRECTORYITEM); T_DIRECTORYITEM tDirItem; // char i, ch = 0; // 讀出根目錄表項 fseek(fpImg, FIRSTOFROOTDIR * BYTESPERSECTOR + iRootDirEntry * size, SEEK_SET); fread(&tDirItem, size, 1, fpImg); // 依次清空 FAT 錶鏈 iFatNext = tDirItem.DIR_FstClus; do { // 這裏可添加數據區扇區清 0 的代碼 // 。。。。。。 nFatValue = ReadFatEntryValue(fpImg, iFatNext); WriteFatEntryValue(fpImg, iFatNext, 0); iFatNext = nFatValue; } while(iFatNext < 0xFF8); // 刪除根目錄區表項 fseek(fpImg, FIRSTOFROOTDIR * BYTESPERSECTOR + iRootDirEntry * size, SEEK_SET); fputc(0xE5, fpImg); // 第一個字符改刪除標識:0xE5 // for(i = 0; i < size; i++) // 所有清 0 // fputc(ch, fpImg); } /* 功能: 向鏡像增長文件 參數表: fpImg = 鏡像文件句柄 fpFile = 源文件句柄 strDirName = 格式化後的文件名 ucFileAttr = 文件屬性 返回值: 無 */ void AddFile(FILE *fpImg, FILE *fpFile, char *strDirName, unsigned char ucFileAttr) { unsigned char ucData[BYTESPERSECTOR]; unsigned long nFileLen; unsigned short arrySectorList[TOTALSECTORS], i, size = sizeof(T_DIRECTORYITEM); unsigned short nNeedSectors, iLast, nRemainderBytes, iRootDirItem; T_DIRECTORYITEM tDirItem; // 取得源文件長度,並計算所需扇區數 fseek(fpFile, 0, SEEK_END); nFileLen = ftell(fpFile); nRemainderBytes = nFileLen % BYTESPERSECTOR; nNeedSectors = nFileLen / BYTESPERSECTOR + (nRemainderBytes > 0 ? 1 : 0); iLast = nNeedSectors - 1; // 尋找 FAT 空表項,同時創建 FAT 錶鏈 arrySectorList[0] = FindEmptyEntryInFat(fpImg, 2); for(i = 1; i < nNeedSectors; i++) { arrySectorList[i] = FindEmptyEntryInFat(fpImg, arrySectorList[i - 1] + 1); WriteFatEntryValue(fpImg, arrySectorList[i - 1], arrySectorList[i]); } WriteFatEntryValue(fpImg, arrySectorList[iLast], 0xFFF); // 根目錄區表項登記 iRootDirItem = FindEmptyEntryInRootDirectory(fpImg); strncpy(tDirItem.DIR_Name, strDirName, 11); tDirItem.DIR_Attr = ucFileAttr; // tDirItem.DIR_WrtTime = ; // tDirItem.DIR_WrtDate = ; tDirItem.DIR_FstClus = arrySectorList[0]; tDirItem.DIR_FileSize = nFileLen; fseek(fpImg, FIRSTOFROOTDIR * BYTESPERSECTOR + iRootDirItem * size, SEEK_SET); fwrite(&tDirItem, size, 1, fpImg); // 拷貝數據到相應扇區 fseek(fpFile, 0, SEEK_SET); for(i = 0; i < iLast; i++) // 最後一個扇區單獨處理(防止不滿 512 字節) { fread(ucData, BYTESPERSECTOR, 1, fpFile); fseek(fpImg, (arrySectorList[i] + FIRSTOFDATA - 2) * BYTESPERSECTOR, SEEK_SET); fwrite(ucData, BYTESPERSECTOR, 1, fpImg); } if(nRemainderBytes > 0) // 最後一個扇區不滿 { fread(ucData, nRemainderBytes, 1, fpFile); for(i = nRemainderBytes; i < BYTESPERSECTOR; i++) ucData[i] = 0; } else // 最後一個扇區也是滿的 fread(ucData, BYTESPERSECTOR, 1, fpFile); fseek(fpImg, (arrySectorList[iLast] + FIRSTOFDATA - 2) * BYTESPERSECTOR, SEEK_SET); fwrite(ucData, BYTESPERSECTOR, 1, fpImg); }
/* img.c 操做 FAT12 文件系統的鏡像文件 四彩 2015-12-08 */ #include <stdio.h> #include <string.h> #include "FAT12.h" // 顯示提示信息 void PrintUsage(char *strFileName); int main(int argc, char *argv[]) { int i; // 顯示提示信息 if((argc == 1) || ((argc == 2) && (!stricmp(argv[1], "-h")))) { PrintUsage(argv[0]); return 0; } // 建立新的空白鏡像文件 if((argc == 3) && (!stricmp(argv[1], "-n"))) { if(CreateNewImg(argv[2])) { printf("Error in creating a new img file : %s !\n", argv[2]); return 1; } return 0; } // 複製引導扇區 if((argc == 4) && (!stricmp(argv[1], "-c"))) { if(CopyBootSector2Img(argv[2], argv[3])) { printf("Error in copying Boot Sector from %s to %s ...\n", argv[3], argv[2]); return 1; } return 0; } // 增長文件 if(((argc >= 4) && (!stricmp(argv[1], "-a")))) { for(i = 3; i < argc; i++) { if(AddFile2Img(argv[2], argv[i], 0)) { printf("Error in adding file %s to %s ...\n", argv[i], argv[2]); return 1; } } return 0; } // 刪除文件 if(((argc >= 4) && (!stricmp(argv[1], "-d")))) { for(i = 3; i < argc; i++) DeleteFileFromImg(argv[2], argv[i]); return 0; } printf("Can't recognize this command.\n"); return 1; } // 顯示提示信息 void PrintUsage(char *strFileName) { printf("Usage: %s <-a | -d | -c | -n | -h> vImg [File1 [File2 ...]]\n", strFileName); printf(" -a Add files to vImg\n"); printf(" -d Delete files from vImg\n"); printf(" -c Copy Boot Sector to vImg\n"); printf(" -n Create a new vImg\n"); printf(" -h Show this usage\n"); }
第一天準備的那個空白 虛擬軟盤文件能夠刪掉了,咱本身隨時能夠建立一個。less
次日那個專門拷貝 Boot Sector 的小程序也能夠刪掉了——這裏已經整合了。函數