Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
6262.pdf
Скачиваний:
34
Добавлен:
13.02.2021
Размер:
6.54 Mб
Скачать

27

Рисунок 1.9 - Структура Partition Table для устройства с GPT

Замечание

Студент постоянно должен помнить о проблемах использования структур языка С, в плане сопоставления их с данными, имеющими прямую адресную привязку.

1.2.3 Системный вызов lseek()

Системный вызов lseek(...) устанавливает позицирование в файле, определенном его дескриптором. В случае успешного завершения операции, возвращается место новой позиции в байтах от начала файла.

Общий формат вызова имеет вид:

#include <sys/types.h>

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

Для вызова этой функции используется три аргумента:

fd — целочисленный номер дескриптора открытого файла; offset — целочисленное значение смещения в байтах; whence — директива, задающая интерпретацию смещения:

SEEK_SET = 0 - смещение устанавливается в offset байт;

SEEK_CUR = 1 - смещение устанавливается как текущее смещение плюс offset байт;

SEEK_END = 2 - смещение устанавливается как размер файла плюс offset

28

байт.

В случае ошибки, функция lseek(...) возвращает значение -1 и необходимо анализировать переменную errno:

EBADF - fd не является дескриптором открытого файла;

ESPIPE - fd ассоциирован с каналом, сокетом или FIFO;

EINVAL - whence не является одним из значений SEEK_SET, SEEK_CUR,

SEEK_END или смещение в файле, которое получилось в результате является отрицательным;

EOVERFLOW - получившееся в результате смещение не может быть представлено типом off_t.

Замечание

Функция lseek() позволяет задавать смещения, которые будут находиться за существующим концом файла, но это не изменяет размер файла. Если позднее по этому смещению будут записаны данные, то последующее чтение в промежутке от конца файла до этого смещения, будет возвращать нулевые байты, пока в этот промежуток не будут фактически записаны данные.

Имеются и другие нововведения, которые мы не будем здесь рассматривать. В любом случае, перед примененим этой функции, следует обратиться к официальному руководству команой: man 2 lseek

Продемострируем возможности функции lseek() на примере задачи анализа содержимого Partition Table, допустим с целью экономии используемой памяти ЭВМ. Для этого:

за основу возьмем исходный текст листинга 1.4;

удалим структуру pt_struct, оставив только нужные поля для записи текущих значений;

размер буфера чтения уменьшим до 4-х байт.

Общий алгоритм работы программы построим следующим образом:

откроем файл, сделаем смещение на местоположение сигнатуры и проверим ее наличие;

сделаем смещение на начало местоположения Partition Table;

в цикле прочитаем и выведем структуру этой таблицы.

На листинге 1.5 представлен вариант реализации такого алгоритма.

Листинг 1.5 — Второй вариант чтения структуры Partition Table

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <linux/hdreg.h> #include <fcntl.h> #include <sys/types.h> #include <errno.h>

29

int main(int argc, char *argv[], char *envp[]) {

printf("Число параметров программы lab1.4: argc=%i\n", argc); if(argc < 2) { // Нет аргумента - завершаем работу

puts("Запусти: sudo ./lab1.4 /dev/sda\n"); return 1;

}

printf("Исследуем устройство: %s\n", argv[1]);

//Введем обозначение типов данных: typedef unsigned char u8;

typedef unsigned short u16; typedef unsigned int u32;

//Нужные поля записи Partition Table

//u8 bootable; // +0 - флаг активности раздела (0 или 80H)

u8 type_part;

//

+4

- системный идентификатор - System ID

u32

sect_before;

//

+8

- число секторов перед разделом

u32

sect_total;

//+12 - размер раздела в секторах (число секторов в разделе)

// Переменные программы

 

int sd;

// Дескриптор файла

ssize_t z;

// Количество считанных байт

off_t of;

// Количество считанных байт

char buf[4];

// Буфер чтения данных

u8 status = 0;

// Рабочая переменная

u16 * ss;

// Рабочая переменная

int i;

// Индекс цикла

// Открываем устройство - только для чтения sd=open(argv[1],O_RDONLY);

if(sd < 0) {

// Если не открыто - завершаем работу

perror(argv[1]);

 

return 2;

 

}else{

printf("Открыт файл %s: с дескриптором = %d\n", argv[1], sd);

}

// Читаем сигнатуру из сектора LBA0 of = lseek(sd, 510, SEEK_SET);

if (of != 510) {

printf("Ошибка: смещение не 510 байт, а %lu\n", of); close(sd);

return 1;

}

z = read(sd, buf, 2);

printf("Прочитали LBA0=%d байт\n", (int)z); if (z != 2) {

puts("Ошибка: прочитали не 2 байта"); close(sd);

return 1;

}

//Проверяем сигнатуру ss = (u16 *)buf;

if (*ss == 0xAA55){

printf("Прочитали сектор MBR: сигнатура = 0x%x\n", *ss); }else{

printf("Ошибка: Это не сектор MBR: сигнатура = 0x%x\n", *ss); return 1;

}

puts("--------------------------"); of = lseek(sd, 446, SEEK_SET);

if (of != 446) {

printf("Ошибка: смещение не 446 байт, а %lu\n", of);

30

close(sd); return 1;

}

//Цикл просмотра Partition Table for (i = 0; i < 4; i++) {

z = read(sd, buf, 4); status = (u8)buf[0];

printf("%i Статус=%x\t", i + 1, status); if ((status != 0) && (status != 0x80)) {

puts(" ошибочный статус");

 

 

of = lseek(sd, 12, SEEK_CUR);

 

 

continue;

 

 

 

}

 

 

 

z = read(sd, buf, 4);

 

 

type_part = (u8)buf[0];

 

 

if (status == 0)

printf("Тип=%x\t

", type_part);

if (status == 0x80) printf("Тип=%x\t*

", type_part);

z = read(sd, (char *)&sect_before,

4);

 

z = read(sd, (char *)&sect_total,

4);

 

printf("Начало=%u\tДлина=%u\n", sect_before, sect_total);

}

close(sd); puts("--------------------------"); puts("Завершили работу...");

return EXIT_SUCCESS;

}

На рисунке 1.10 представлен вывод программы, приведенной на листинге 1.5. Хорошо видно, что содержимое этого рисунка, с точностью до деталей, совпадает с выводом программы, представленной на рисунке 1.8.

Рисунок 1.10 — Второй вариант чтения структуры Partition Table

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]