W dzisiejszym artykule, tak jak mówi jego tytuł, zajmiemy się zaawansowaną obsługą dysków i plików. Będziemy mogli odczytać takie rzeczy jak np. budowa dysku twardego lub informacje o systemie plików. Aha, zaznaczam, że wszystko co napisałem może nie działać na Win95/98/Me. Tak więc przejdźmy do rzeczy. Najważniejszą funkcją, jakiej będziemy używać, będzie funkcja DeviceIoControl, a wygląda ona tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
BOOL DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped ); |
Omówmy po kolei wszystkie parametry:
hDevice – uchwyt do urządzenia, na którym będziemy wykonywać operację
dwIoControlCode – kod przeprowadzanej operacji
lpInBuffer – wskaźnik do bufora wejścia, który zawiera informacje potrzebne do przeprowadzenia operacji, zależy od dwIoControlCode
nInBufferSize – rozmiar lpInBuffer
lpOutBuffer – wskaźnik do bufora wyjściowego, zawiera informacje zwrócone podczas operacji, zależy od dwIoControlCode
nOutBufferSize – rozmiar lpOutBufferSize
lpBytesReturned – wskaźnik na liczbę type DWORD, zawiera liczbę bajtów zwróconych do lpOutBuffer
lpOverlapped – wskaźnik na strukturę typu OVERLAPPED
Pierwszy parametr uzyskujemy używając funkcji CreateFile z odpowiednimi parametrami. Aby otworzyć urządzenie używamy CreateFile z parametrem lpFileName: \\\\.\\NazwaUrządzenia (np. \\\\.\\d:)
Funkcja (DeviceIoControl) zwraca wartość 0 jeżeli się nie powiodła, lub inną wartość w przypadku powodzenia.
Poznamy teraz przykładowe kody operacji do użycia w funkcji DeviceIoControl:
FSCTL_GET_COMPRESSION – zwraca stan kompresji pliku lub katalogu
IOCTL_DISK_GET_LENGTH_INFO – zwraca długość dysku lub partycji
IOCTL_DISK_IS_WRITABLE – informuje, czy podane urządzenie jest zapisywalne
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX – zwraca rozszerzone informacji o fizycznym dysku
IOCTL_DISK_GET_PARTITION_INFO_EX – zwraca rozszerzone informacje o partycji
Oczywiście nie może objeść się przez przykładu zastosowania:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
// Rafał Krajewski // przykład zastosowania funkcji DeviceIoControl // kod: IOCTL_DISK_GET_PARTITION_INFO_EX #include #include #include #include int main() { PARTITION_INFORMATION_EX p; DWORD d; HANDLE h=CreateFile("\\\\.\\c:",FILE_ALL_ACCESS,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); if (h==INVALID_HANDLE_VALUE) { printf("Nie można otworzyc urzadzenia!"); return 0; } DeviceIoControl(h,IOCTL_DISK_GET_PARTITION_INFO_EX,NULL,0,&p,sizeof(p),&d,NULL); CloseHandle(h); printf("Offset partycji: %I64d bajtow\n",p.StartingOffset); printf("Rozmiar partycji: %I64d bajtow\n",p.PartitionLength); printf("Format partycji: "); if (p.PartitionStyle==PARTITION_STYLE_MBR) { printf("MBR\n"); if (p.Mbr.BootIndicator==true) printf("Partycja rozruchowa: tak\n"); else printf("Partycja rozruchowa: nie\n"); printf("Ukryte sektory: %ld\n",p.Mbr.HiddenSectors); } if (p.PartitionStyle==PARTITION_STYLE_GPT) { printf("GPT\n"); printf("Nazwa partycji: %s\n",p.Gpt.Name); } if (p.PartitionStyle==PARTITION_STYLE_RAW) printf("RAW\n"); printf("Numer partycji: %d",p.PartitionNumber); getch(); return 0; } |
I jeszcze jeden przykład, z innym kodem operacji:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
// Rafał Krajewski // przykład zastosowania funkcji DeviceIoControl // kod: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX #include #include #include #include int main() { DISK_GEOMETRY_EX p; DWORD d; // podajemy partycję, ale informacje wyświetlane są o całym dysku na którym // jest partycja HANDLE h=CreateFile("\\\\.\\c:",FILE_ALL_ACCESS,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); if (h==INVALID_HANDLE_VALUE) { printf("Nie mozna otworzyc urzadzenia!"); return 0; } DeviceIoControl(h,IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,NULL,0,&p,sizeof(p),&d,NULL); printf("Rozmiar dysku: %I64d bajtow\n",p.DiskSize); printf("Cylindry: %I64d\n",p.Geometry.Cylinders); printf("Sciezek na cylinder: %ld\n",p.Geometry.TracksPerCylinder); printf("Sektorow na sciezkę: %ld\n",p.Geometry.SectorsPerTrack); printf("Bajtow na sektor: %ld\n",p.Geometry.BytesPerSector); CloseHandle(h); getch(); return 0; } |
Teraz mała dygresja. Chociaż ten art nie traktuje o budowie dysku, warto się z nią zapoznać, żeby dobrze rozumieć powyższy kod.
Podstawowe pojęcia to:
sektor – najmniejszy ciągły obszar adresowany za pomocą pojedynczych operacji, wycinek ścieżki, zwykle o rozmiarze 512 bajtów
ścieżka – zbiór sektorów dyskowych dostępny dla głowicy czytająco piszącej w jednym z jej położeń, wiele ścieżek tworzy współśrodkowe pierścienie
cylinder – zbiór ścieżek o tym samym numerze umieszczonych na wszystkich powierzchniach roboczych dysku, ścieżki cylindra są dostępne dla zespołu głowic czytająco-piszących bez zmiany położenia głowic
Jest jeszcze mnóstwo innych zastosowań funkcji DeviceIoControl. Jak pokazałem dwa, lecz nic nie stoi na przeszkodzie, abyście poznali resztę. Więc informacji oczywiście na stronie Microsoftu i w Platform SDK. Mogę dodać, że dzięki tej funkcji możecie stworzyć nową partycję, lub powiększyć istniejącą a także formatować i defragmentować dyski. A więc na co czekacie, do dzieła! 🙂
Autor: krajew4