Міністерство освіти і науки
Національний університет „Львівська політехніка”
Кафедра EОМ
/
Звіт
до лабораторної роботи № 4
з дисципліни: “Системне програмне забезпечення”
Мета: створити програму, яка перевіряє Flash-накопичувачі на наявність битих секторів.
Теоретичні відомості
У процесі експлуатації магнітних носіїв неминуче виникають різні помилки - дефекти, які потрібно вчасно виявляти й усувати. Зустрічаються на дисках дефекти можна розділити на два типи – фізичні і логічні.
Логічні дефекти - пошкодження файлової структури або компонентів системної області диска. Найбільш часто поширюваними дефектами є:
втрачені кластери - такі кластери, які вважаються зайнятими деякими файлами або папками, але в дійсності такими не є (на ці файли є помилкові посилання із системної області);
пересічні файли - файли, що використовують загальні кластери.
Логічні дефекти призводять до забруднення дискового простору (саме це відбувається при утворенні загублених кластерів), до неможливості доступу до фрагментів файлової системи, до взаємовпливу пересічних файлів. Логічні дефекти можуть привести до знищення частини даних на диску.
Фізичні дефекти пов'язані з механічними пошкодженнями, низькою якістю або старінням магнітної поверхні. Якщо носій пошкоджений фізично, то з нього неможливо зчитати інформацію або правильно записати нову.
Одним з видів дефектів є наявність битих секторів. Практично всі диски мають биті розділи. Він може бути один або кілька, і в більшості випадків це не страшно. Але з часом їх стає все більше, і вони все сильніше ускладнюють оперування інформацією на носії. Такі ділянки можна виявити скануванням жорсткого диска на биті сектори спеціальними утилітами. Причин появи бед секторів може бути багато: удар диска або використання в неправильних умовах; переривання запису шляхом відключення живлення; перегріви і температурні скачки; природний знос головок і пише диска; неякісна продукція. Тут же можна обробити биті сектори на невідновлювані та відновлювані. До перших належать ті, що викликані ударом або перегрівом. Вони знищуються один раз і не підлягають відновленню, а інформація, як правило, безповоротно зникає. Другий тип бед секторів з'являється в результаті обриву процесу запису. Їх можна реанімувати шляхом звичайної перезапису диска.
Код програми
#ifndef UNICODE
# define UNICODE
#endif
#ifndef _UNICODE
# define _UNICODE
#endif
#define STRICT
#pragma warning( disable : 4115 )// named type definition in parentheses
#include <windows.h>
#pragma warning( disable : 4201 )// nonstandard extension used : nameless struct/union)
#include <winioctl.h>
#include <crtdbg.h>
#include <stdio.h>
#pragma warning ( disable : 4127 ) // conditional expression is constant
#pragma comment(linker, "/subsystem:console")
#pragma comment(lib, "advapi32.lib" )
#pragma comment(lib, "kernel32.lib" )
#pragma intrinsic(memcpy, memset, memcmp, strlen)
#ifndef ARRSIZE
#define ARRSIZE(x) (sizeof((x))/sizeof((x)[0]))
#endif
#ifdef _DEBUG
#define VERIFY(f) _ASSERT(f)
#else
#define VERIFY(f) ((void)(f))
#endif
#define BYTES_PER_SECTOR 512
///////////////////////////////////////////////////////////
// GetSectorsPerDisk
//
// Returns the size of hard disk
// 0 means error
///////////////////////////////////////////////////////////
__inline
UINT64
GetSectorsPerDisk(
IN HANDLE hDisk
)
{
DWORD Tmp;
PARTITION_INFORMATION PartInfo;
if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_PARTITION_INFO,
NULL, 0,
&PartInfo, sizeof(PartInfo),
&Tmp, NULL))
{
return 0;
}
return PartInfo.PartitionLength.QuadPart / BYTES_PER_SECTOR;
}
//
// Simple fragment description
//
typedef struct {
UINT64 Start; // Start sector of fragment
unsigned long Size; // Length of fragment
} t_Range;
///////////////////////////////////////////////////////////
// CheckRange
//
// Checks given range of sectors
// Returns FALSE if range contains bad blocks
///////////////////////////////////////////////////////////
__inline
BOOL
CheckRange(
IN HANDLE hDisk,
IN const t_Range* Range
)
{
DWORD Tmp;
VERIFY_INFORMATION VerifyInfo;
// Translate sectors to bytes
VerifyInfo.StartingOffset.QuadPart = Range->Start * BYTES_PER_SECTOR;
VerifyInfo.Length = Range->Size * BYTES_PER_SECTOR;
return DeviceIoControl(hDisk, IOCTL_DISK_VERIFY,
&VerifyInfo, sizeof(VerifyInfo),
NULL, 0, &Tmp, NULL);
}
///////////////////////////////////////////////////////////
// ReassignRange
//
// Reassigns given range of sectors
// Returns FALSE if error
///////////////////////////////////////////////////////////
__inline
BOOL
ReassignRange(
IN HANDLE hDisk,
IN const t_Range* Range
)
{
DWORD Tmp;
DWORD BlocksSize;
REASSIGN_BLOCKS* Blocks;
if (0 == Range->Size)
return TRUE;
_ASSERTE(Range->Size < 0x10000);
BlocksSize = sizeof(REASSIGN_BLOCKS) + (Range->Size - 1) * sizeof(DWORD);
Blocks = (REASSIGN_BLOCKS*)_alloca(BlocksSize);
Blocks->Reserved = 0;
Blocks->Count = (USHORT)Range->Size;
for (Tmp = 0; Tmp < Range->Size; Tmp++)
Blocks->BlockNumber[Tmp] = (DWORD)(Range->Start + Tmp);
return DeviceIoControl(hDisk, IOCTL_DISK_REASSIGN_BLOCKS,
Blocks, BlocksSize,
NULL, 0, &Tmp, NULL);
}
const unsigned long MaxSectorsInVerify = 512;
///////////////////////////////////////////////////////////
// wmain
//
//
///////////////////////////////////////////////////////////
int
__cdecl
wmain(
IN int argc,
IN wchar_t** argv
)
{
t_Range Range[22]; // Array of ranges
WCHAR szDisk[32]; // Helper array to open disk
HANDLE hDisk; // Handle of disk to check
UINT64 Tmp, SectorsPerDisk; // The size of disk in sectors
unsigned long SectorsPerChunk; // Chunk size in sectors
unsigned long Percent; // Used to show current percent
unsigned long nBadBlocks; // Total number of bad blocks
unsigned long nFixedBadBlocks; // Total number of fixed blocks
BOOL bReassignError;
BOOL bFix;
//
// Parse command line
//
if (argc <= 1)
{
const wchar_t* name = wcsrchr(argv[0], L'\\');
if (NULL == name)
name = argv[0];
else
name = name + 1;
fwprintf(stderr, L"\nUse %s N [-r] \nWhere N is a disk number to check for bad blocks\n", name);
return -1;
}
//
// Parse "-r" argument
//
bFix = argc >= 3 && 0 == wcsicmp(argv[2], L"-r");
//
// Open physical disk
//
_snwprintf(szDisk, ARRSIZE(szDisk), L"\\\\.\\PhysicalDrive%s", argv[1]);
hDisk = CreateFileW(szDisk, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hDisk)
{
fwprintf(stderr, L"Can't open \"%s\"\n", szDisk);
return -1;
}
//
// Get the number of sectors to check
//
SectorsPerDisk = GetSectorsPerDisk(hDisk);
fwprintf(stdout, L"The size of disk is %lu.%02lu Gb\n",
(DWORD)(SectorsPerDisk >> 21),
((((DWORD)SectorsPerDisk) & 0x3FFFFF) * 100) >> 21);
//
// Calculate chunk size
//
Tmp = SectorsPerDisk / 20;
if (Tmp < MaxSectorsInVerify)
SectorsPerChunk = (DWORD)(Tmp);
else
SectorsPerChunk = MaxSectorsInVerify;
//
// Init main cycle
//
Percent = ~0UL;
nBadBlocks = 0;
nFixedBadBlocks = 0;
bReassignError = FALSE;
Range[0].Size = SectorsPerChunk;
for (Range[0].Start = 0; Range[0].Start < SectorsPerDisk; Range[0].Start += Range[0].Size)
{
unsigned long i, n, NewPercent;
//
// Correct the length of last range
//
Tmp = SectorsPerDisk - Range[0].Start;
if (Tmp < SectorsPerChunk)
Range[0].Size = (DWORD)(Tmp);
//
// Show new percent
//
NewPercent = (DWORD)(((Range[0].Start + Range[0].Size) * 100) / SectorsPerDisk);
if (NewPercent != Percent)
{
Percent = NewPercent;
fwprintf(stdout, L"%d%%\r", Percent);
}
//
// Do recursive search
//
for (i = 0, n = 1; i < n; ++i)
{
// Check current range
if (CheckRange(hDisk, Range + i))
continue;
//
// Try to improve precision. Use bisection method
//
if (n + 2 > ARRSIZE(Range) || 1 == Range[i].Size)
{
nBadBlocks += Range[i].Size;
fwprintf(stdout, L"Bad block found: [0x%I64x 0x%lx]\n",
Range[i].Start,
Range[i].Size);
if (bFix && !bReassignError)
{
if (!ReassignRange(hDisk, Range + i))
bReassignError = TRUE;
else
{
VERIFY(CheckRange(hDisk, Range + i));
nFixedBadBlocks += Range[i].Size;
}
}
}
else
{
// Split range
unsigned long Half = Range[i].Size / 2;
Range[n].Start = Range[i].Start;
Range[n].Size = Half;
Range[n + 1].Start = Range[i].Start + Half;
Range[n + 1].Size = Range[i].Size - Half;
n += 2;
}
}
}
VERIFY(CloseHandle(hDisk));
//
// Show report
//
fwprintf(stdout, L"Total number of found bad sectors %lu\n", nBadBlocks);
if (bFix && 0 != nBadBlocks)
fwprintf(stdout, L"Total number of remapped bad sectors %lu\n", nFixedBadBlocks);
//
// Exit to Windows
//
return 0;
}
Результат виконання програми
/
Рис. 1. Результат виконання перевірки.
Висновок: на цій лабораторній роботі я ознайомився з типами пошкоджень дисків та розробив програму для курсової роботи, яка перевіряє Flash-накопичувачі на наявність битих секторів.