Книга: Восстановление данных. Практическое руководство

Структура UFS

Структура UFS

В целом, UFS очень похожа на ext2fs — те же inode, блоки данных, файлы, каталоги. Тем не менее, есть между этими файловыми системами и различия. В ext2fs имеется только одна группа индексных дескрипторов (inodes), и только одна группа блоков данных для всего раздела. В отличие от ext2fs, UFS делит раздел на несколько зон одинакового размера, называемых группами цилиндров. Каждая зона имеет свою группу индексных дескрипторов и свою группу блоков данных, независимых ото всех остальных зон. Иначе говоря, индексные дескрипторы описывают блоки данных той и только той зоны, к которой они принадлежат. Это повышает быстродействие файловой системы, так как головка жесткого диска совершает более короткие перемещения. Кроме того, такая организация упрощает процедуру восстановления при значительном разрушении данных, поскольку, как показывает практика, обычно гибнет только первая группа индексных дескрипторов. Случаи, когда гибнут все группы, встречаются крайне редко. Предполагаю, что для того, чтобы умышленно этого добиться, диск потребуется положить под гидравлический пресс.

Диаграмма, осуществляющая сравнение файловых систем s5 и UFS, представлена на рис. 8.9. В UFS каждый блок разбит на несколько фрагментов фиксированного размера, предотвращающих потерю свободного пространства в хвостах файлов. В результате этого использование блоков большого размера уже не кажется расточительной идеей, напротив, это увеличивает производительность и уменьшает фрагментацию. Если файл использует более одного фрагмента в двух несмежных блоках, он автоматически перемещается на новое место, в наименее фрагментированный регион свободного пространства. Таким образом, фрагментация в UFS очень мала или же совсем отсутствует, что существенно облегчает восстановление удаленных файлов и разрушенных данных.


Рис. 8.9. Структура файловых систем s5/ext2fs (а) и UFS (б)

Адресация ведется либо по физическим смещениям, измеряемым в байтах и отсчитываемым от начала группы цилиндров (реже — от начала раздела UFS), либо в номерах фрагментов, отсчитываемых от тех же самых точек. Допустим, размер блока составляет 16 Кбайт, разбитых на 8 фрагментов. Тогда 69-й сектор будет иметь смещение 512 * 69 == 35328 байт или 1024 * (16/8)/512 * 69 == 276 фрагментов.

В начале раздела расположен загрузочный сектор, затем следует суперблок, за которым находится одна или несколько групп цилиндров (рис. 8.10). Для перестраховки копия суперблока дублируется в каждой группе. Загрузочный сектор не дублируется, но по соображениям унификации и единообразия под него просто выделяется место, таким образом, относительная адресация блоков в каждой группе остается неизменной.


Рис. 8.10. Последовательно расположенные группы цилиндров

В UFS суперблок располагается по смещению 8192 байт от начала раздела, что соответствует 16-му сектору. В UFS2 он "переехал" на 65536 байт (128 секторов) от начала, освобождая место для дисковой метки и первичного загрузчика операционной системы, а для действительно больших (в исходных текстах они обозначены как "piggy") систем предусмотрена возможность перемещения суперблока по адресу 262144 байт (целых 512 секторов).

Среди прочей информации суперблок содержит:

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

fs_iblkno — смещение первого inode в первой группе цилиндров (фрагменты от начала раздела);

fs_dblkno — смещение первого блока данных в первой группе цилиндров (фрагменты от начала раздела);

fs_ncg — количество групп цилиндров;

fs_bsize — размер одного блока в байтах;

fs_fsize — размер одного фрагмента в байтах;

fs_frag — количество фрагментов в блоке;

fs_fpg — размер каждой группы цилиндров, выраженный в блоках (также может быть найден через fs_cgsize).

Для перевода смещений, выраженных во фрагментах, в номера секторов, служит следующая формула: sec_n(fragment_offset) == fragment_offset* (fs_bsize/fs_frag/512) или ее более короткая разновидность: sec_n(fragment_offset) == fragment_offset*fs_fsize /512.

Структура суперблока определена в файле /src/ufs/ffs/fs.h и в упрощенном виде выглядит, как показано в листинге 8.7.

Листинг 8.7. Формат суперблока (второстепенные поля опущены)

struct fs {
/* 0x00 */ int32_t fs_firstfield;    /* Связный список файловых систем */
/* 0x04 */ int32_t fs_unused_1;      /* для внутренних суперблоков */
/* 0x08 */ ufs_daddr_t fs_sblkno;
 /* Адрес суперблока в файловой системе (фс) */
/* 0x0C */ ufs_daddr_t fs_cblkno;    /* Смещение блока цилиндров в фс */
/* 0x10 */ ufs_daddr_t fs_iblkno;    /* Смещение блоков inode в фс */
/* 0x14 */ ufs_daddr_t fs_dblkno;    /* Смещение 1-го блока данных после
                                        группы цил. */
/* 0x18 */ int32_t fs_cgoffset;      /* Смещение группы цилиндров */
/* 0x1C */ int32_t fs_cgmask;        /* Используется в calc mod fs_ntrak */
/* 0x20 */ time_t  fs_time;          /* Время последней записи */
/* 0x24 */ int32_t fs_size;          /* Количество блоков в фс */
/* 0x28 */ int32_t fs_dsize;         /* Количество блоков данных в фс */
/* 0х2С */ int32_t fs_nog;           /* Количество групп цилиндров */
/* 0x30 */ int32_t fs_bsize;         /* Размер базовых блоков в фс */
/* 0x34 */ int32_t fs_fsize;         /* Размер фрагментов блоков в фс */
/* 0x38 */ int32_t fs_frag;          /* Количество фрагментов в блоке в фс */
/* Параметры конфигурации */
/* 0x3C */ int32_t fs_minfree;       /* Мин. процент свободных блоков */
/* 0x40 */ int32_t fs_rotdelay;      /* Мин. задержка (мс) для оптимального
                                        след. блока */
/* 0x44 */ int32_t fs_rps;           /* Обороты диска в минуту */
/* Размеры, определяемое кол-вом гц и их размерами */
/* 0x98 */ ufs_daddr_t fs_csaddr;     /* Адрес блока информации гц */
/* 0х9С */ int32_t fs_cssize;         /* Размер блока информации гц */
/* 0xA0 */ int32_t fs_cgsize;         /* Размер группы цилиндров */
/* Поля, которые могут быть вычислены на основании остальных */
/* 0хВ4 */ int32_t fs_cpg;             /* Кол-во цилиндров в группе */
/* 0xB8 */ int32_t fs_ipg;             /* Кол-во Inode на группу */
/* 0xBC */ int32_t fs_fpg;             /* Кол-во блоков в группе * fs_frag */
/* Поля, очищаемые при монтировании */
/* 0xD0 */ int8_t fs_fmod;             /* Флаг модификации суперблока */
/* 0xD1 */ int8_t fs_clean;            /* Флаг "чистой" (clean) фс */
/* 0xD2 */ int8_t fs_ronly;            /* Флаг защиты от записи */
/* 0xD3 */ int8_t fs_flags;            /* См. поле fs_ flags */
/* 0xD4 */ u_char fs_fsmnt[MAXMNTLEN]; /* Путь монтирования фс */
};

За концом суперблока, на некотором отдалении от него, находится первая группа цилиндров. В начале каждой группы расположена служебная структура cg, представляющая собой описатель группы цилиндров и содержащая магическую последовательность 55h 02h 09h, по которой все уцелевшие группы можно найти даже при полностью испорченном суперблоке. Штатным образом стартовые адреса всех последующих групп вычисляются путем умножения номера группы на ее размер, содержащийся в поле fs_cgsize.

Другие важные параметры:

cg_cgx — порядковый номер группы, отсчитываемый от нуля;

cg_old_niblk — количество inode в данной группе;

cg_ndblk — количество блоков данных в данной группе;

csum — количество свободных inode и блоков данных в данной группе;

cg_iusedoff — смещение карты занятых inode, отсчитываемое от начала данной группы (в байтах);

cg_freeoff — смещение карты свободного пространства (байты от начала группы).

Структура cg определена в файле /src/ufs/ffs/fs.h и выглядит следующим образом — листинг 8.8.

Листинг 8.8. Структура описателя группы цилиндров

#define СG_MAGIC 0x090255
#define MAXFRAG 8
struct cg {
/* 0x00 */ int32_t cg_firstfield;     /* Связный список групп цилиндров */
/* 0x04 */ int32_t cg_magic;          /* Магическая последовательность */
/* 0x08 */ int32_t cg_old_time;       /* Время последней записи */
/* 0x0C */ int32_t cg_cgx;            /* Мы находимся в гц номер cgx */
/* 0x10 */ int16_t cg_old_ncyl;       /* Кол-во цилиндров в этой гц */
/* 0x12 */ int16_t cg_old_niblk;      /* Кол-во блоков inode в этой гц */
/* 0x14 */ int32_t cg_ndblk;          /* Кол-во блоков данных в этой гц */
/* 0x18 */ struct csum cg_cs;         /* Краткое описание цилиндра */
/* 0x28 */ int32_t cg_rotor;          /* Положение посл. исп. блока */
/* 0x2C */ int32_t cg_frotor;         /* Положение посл. исп. фрагмента */
/* 0x30 */ int32_t cg_irotor;         /* Положение посл. исп. inode */
/* 0x34 */ int32_t cg_frsum[MAXFRAG]; /* Счетчик доступных фрагментов */
/* 0x54 */ int32_t cg_old_btotoff;    /* (int32) блоков на цилиндр */
/* 0x58 */ int32_t cg_old_boff;       /* (u_int16) своб. позиций блоков */
/* 0x5C */ int32_t cg_iusedoff;       /* (u_int8) карта исп. inode */
/* 0x60 */ int32_t сg_freeoff;        /* (u_int8) карта своб. блоков */
/* 0x64 */ int32_t cg_nextfreeoff;    /* (u_int8) след. своб. блок */
/* 0x68 */ int32_t cg_clustersumoff;  /* (u_int32) счетчик своб. кластеров */
/* 0x6C */ int32_t cg_clusteroff;     /* (u_int8) карта своб. кластеров */
/* 0x70 */ int32_t cg_nclusterblks;   /* Кол-во кластеров в этой гц */
/* 0x74 */ int32_t cg_niblk;          /* Кол-во блоков inode в этой гц */
/* 0x78 */ int32_t cg_initediblk;     /* Посл. инициализированный inode */
/* 0х7С */ int32_t cg_sparecon32[3];  /* Зарезервировано */
/* 0x00 */ ufs_time_t cg_time;        /* Время последней записи */
/* 0x00 */ int64_t cg_sparecon64[3];  /* Зарезервировано */
/* 0x00 */ u_int8_t cg_space[1];      /* Место для карт гц */
/* реально больше */

Между описателем группы цилиндров и группой inode расположены карта занятых inode и карта свободного дискового пространства, представляющие собой обыкновенные битовые поля, точно такие же, как и в NTFS. При восстановлении удаленных файлов без этих карт обойтись невозможно. Они существенно сужают круг поиска, что особенно хорошо заметно на дисках, заполненных более чем наполовину.

За картами следует массив inode, смещение которого содержится в поле cg_iusedoff (адрес первой группы inode продублирован в суперблоке). По сути, в UFS структура inode ничем не отличается от ext2fs, только расположение полей другое. К тому же, имеется только один блок косвенной адресации вместо трех, но это уже детали, не имеющие большого практического значения. Рассмотрим назначение фундаментальных полей, к числу которых принадлежат:

di_nlink — количество ссылок на файл (0 означает "удален");

di_size — размер файла в байтах;

di_atime/di_atimensec — время последнего доступа к файлу;

di_mtime/di_mtimensec — время последней модификации;

di_ctime/di_ctimensec — время последнего изменения inode;

di_db — адреса первых 12 блоков данных файла, отсчитываемые во фрагментах от начала группы цилиндров;

di_ib — адрес блоков косвенной адресации (фрагменты от начала группы).

Сама структура inode определена в файле /src/ufs/ufs/dinode.h. Для UFS1 эта структура выглядит, как показано в листинге 8.9 и на рис. 8.11.


Рис. 8.11. Схематичное изображение inode

Листинг 8.9. Структура inode в UFS1

struct dinode {
/* 0x00 */ uint16_t di_mode;          /*   0: IFMT, права доступа; */
                                      /*      см. ниже */
/* 0x02 */ int16_t  di_nlink;         /*   2: Счетчик ссылок */
/* 0x04 */ union {
            uint16_t oldids[2];       /*   4: Ffs: старые ID */
                                      /*      пользователя и группы */
            int32_t  inumber;         /*   4: Lfs: номер inode */
           } di_u;
/* 0x08 */ u_int64_t   di_size;       /*   8: Счетчик байтов файла */
/* 0x10 */ int32_t     di_atime;      /*  16: Время последнего доступа */
/* 0x14 */ int32_t     di_atimensec;  /*  20: Время последнего доступа */
/* 0x18 */ int32_t     di_mtime;      /*  24: Время последней */
                                      /*      модификации */
/* 0x1C */ int32_t     di_mtimensec;  /*  28: Время последней */
                                      /*      модификации */
/* 0x20 */ int32_t     di_ctime;      /*  32: Время последнего */
                                      /*      изменения inode */
/* 0x24 */ int32_t     di_ctimensec;  /*  36: Время последнего */
                                      /*      изменения inode */
/* 0x28 */ ufs_daddr_t di_db[NDADDR]; /*  40: Непоср. дисковые блоки */
/* 0x58 */ ufs_daddr_t di_ib[NIADDR]; /*  88: Косв. дисковые блоки */
/* 0x64 */ u_int32_t   di_flags;      /* 100: Флаги статуса (chflags) */
/* 0x68 */ int32_t     di_blocks;     /* 104: Факт, занятые блоки */
/* 0x6C */ int32_t     di_gen;        /* 108: Номер генерации */
/* 0x70 */ u_int32_t   di_uid;        /* 112: Владелец файла */
/* 0x74 */ u_int32_t   di_gid;        /* 116: Группа файла */
/* 0x78 */ int32_t     di_spare[2];   /* 120: Зарезервировано */
};

В UFS2 формат inode был существенно изменен — появилось множество новых полей, удвоилась ширина адресных полей (листинг 8.10). Что это обозначает для нас в практическом плане? Смещения всех полей изменились, только и всего, а общий принцип работы с индексными дескрипторами остался прежним.

Листинг 8.10. Структура inode в USF2

struct ufs2_dinode {
/* 0x00 */ u_int16_t    di_mode;         /*   0: IFNT, права доступа; */
                                         /*      см. ниже */
/* 0x02 */ int16_t      di_nlink;        /*   2: Счетчик ссылок */
/* 0x04 */ u_int32_t    di_uid;          /*   4: Владелец файла */
/* 0x08 */ u_int32_t    di_gid;          /*   8: Группа файла */
/* 0x0C */ u_int32_t    di_blksize;      /*  12: Размер блока Inode */
/* 0x10 */ u_int64_t    di_size;         /*  16: Счетчик байтов файла */
/* 0x18 */ u_int64_t    di_blocks;       /*  24: Практически занятые байты */
/* 0x20 */ ufs_time_t   di_atime;        /*  32: Время последнего доступа */
/* 0x28 */ ufs_time_t   di_mtime;        /*  40: Время последней */
                                         /*      модификации */
/* 0x30 */ ufs_time_t   di_ctime;        /*  48: Время последнего */
                                         /*      изменения inode */
/* 0x38 */ ufs_time_t   di_birthtime;    /*  56: Время создания Inode */
/* 0x40 */ int32_t      di_mtimensec;    /*  64: Время последней */
                                         /*      модификации */
/* 0x44 */ int32_t      di_atimensec;    /*  68: Время последнего доступа */
/* 0x48 */ int32_t      di_ctimensec;    /*  72: Время последнего доступа */
/* 0x4C */ int32_t      di_birthnsec;    /*  76: Время создания Inode */
/* 0x50 */ int32_t      di_gen;          /*  80: Номер генерации */
/* 0x54 */ u_int32_t    di_kernflags;    /*  84: Флаги ядра */
/* 0x58 */ u_int32_t    di_flags;        /*  88: Флаги статуса (chflags) */
/* 0x5C */ int32_t      di_extsize;      /*  92: Блок внешних атрибутов */
/* 0x60 */ ufs2_daddr_t di_extb[NXADDR]; /*  96: Блок внешних атрибутов */
/* 0x70 */ ufs2_daddr_t di_db[NDADDR];   /* 112: Непоср. дисковые блоки */
/* 0xD0 */ ufs2_daddr_t di_ib[NIADDR];   /* 208: Косв. дисковые блоки */
/* 0xE8 */ int64_t      di_spare[3];     /* 232: Зарезервировано */
};

Имена файлов хранятся в каталогах (рис. 8.12). В индексных дескрипторах их нет. С точки зрения UFS, каталоги являются файлами особого типа и могут храниться по любому адресу, принадлежащему группе цилиндров. Файловая система UFS поддерживает несколько типов хеширования каталогов, однако на структуре хранения имен это никак не отражается. Имена хранятся в блоках, называемых DIRBLKSIZ, в структурах типа direct, выровненных по 4-х байтной границе.


Рис. 8.12. Хранение имен файлов и каталогов

Структура direct определена в файле /src/ufs/ufs/dir.h (листинг 8.11) и содержит: номер inode, описывающий данный файл, тип файла, его имя, а также длину самой структуры direct, используемую для нахождения следующей структуры этого типа в блоке.

Листинг 8.11. Структура direct, отвечающая за хранение имен файлов и каталогов

struct direct {
/* 0x00 */ u_int32_t d_ino;                 /* Номер inode данной записи */
/* 0x04 */ u_int16_t d_reclen;              /* Длина данной записи */
/* 0x06 */ u_int8_t  d_type;                /* Тип файла, см. ниже */
/* 0x07 */ u_int8_t  d_namlen;              /* Длина строки в d_name */
/* 0x08 */ char      d_name[MAXNAMLEN + 1]; /* Имя с длиной <= MAXNAMLEN */
};

На этом описание файловой системы UFS можно считать законченным. Для ручного восстановления данных приведенной информации вполне достаточно.

Оглавление книги


Генерация: 1.161. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз