На сколько я понимаю, ни одна FAT (ну точно не FAT12) не поддерживает восстановление данных после сбоев компьютера. Я прав?
Гарантировать себя от сбоев (прерываний) невозможно, поэтому лепят что-то типа транзакций. При начале файловой операции вы "открываете" транзакцию (запоминая что и как будете делать и инфа для rollback). Далее до завершения (успех) операция не считается закрытой. После рестарта (аварийного) ваша система находит незакрытую транзацию и (наверное) откатывает все по дефолту либо предлагает оставить полузаписанное что-то (иногда лучше чего-то чем совсем ничего). Про FAT не знаю но знаю что были специальные утилиты восстановления битых файлов что косвенно подтверждает вашу догадку.
Всем доброго вечера! Вроде бы завершил придумывать свою файловую систему. Теперь буду писать несколько утилит, для того чтобы можно было создавать образы, форматировать дискеты и бродить по просторам файловой системы. Почитать про мою новую файловую систему Вы сможете по этой ссылке: http://dubrovkin.h18.ru/DFS-FD.htm. Жду Ваших комментариев!
Владимир Кулаков: Программирование дисковых подсистем. Почти 800 страниц. Есть примеры. Поищите в сети.
s3dworld А теперь по этой структуре покажи нам хекс дамп ФС с размещением там нескольких файлов, разных размеров. С выделением в хексе, какая порция данных относится к какому файлу. Мы посмотрим.
TermoSINteZ Если честно, то не понял о чём Вы. Что значит: > С выделением в хексе, какая порция данных относится к какому файлу. У меня не может быть так, чтобы в одном кластере лежали данные разных файлов.
s3dworld Тогда покажи как может быть. А если файл вмещается в 1 кластер? Тогда что? Я о том что вот вы показываете хекс дамп. Выделяете разным цветом последовательности байт и показываете стрелочками "тут лежит имя файла, тут лежит размер, тут смещение, тут сами данные..." и так далее.
Полностью согласен, что моя файловая система очень уж громоздка. Я решил почитать спецификацию по FAT (http://www.gamedev.ru/files/?id=62689). Так же почитал статью: http://www.avprog.narod.ru/progs/fat.html#02h. Решил написать для себя подобие FAT. По сути всё очень просто. Но есть несколько моментов, которые хочу чтобы Вы мне уточнили. МОМЕНТ 1 В FAT может быть две области с описанием (характеристиками, цепочками) кластеров. То есть будет ли их две или одна, это по желанию. Корневая папка только одна. И как я понял, никакая папка не дублируется. И данные файлов тоже не дублируются, даже очень важные? То есть я имею в виду, что у нас может быть папка Soft в корневой папке. А в этой папке будет ещё папка Paint. Но может получиться так, что кластеры, где располагаются элементы этой папки, повреждены. И что, тогда мы просто-напросто потеряли не только ветвь развития, но и занятые кластеры? Как это реализуется, чтобы не потерять след. И собственно тоже самое касается файлов, не именно описания файла (то что находится в списке папки), а именно содержимое файла. Дублируется ли оно или как происходит. А то ведь так можно навсегда потерять данные в случае порчи сектора кластера. А если есть дубляж, то можно из дубля взять данные и поправить кластеры оригинала. Только тогда при каждой операции записи, нужно делать двойную работы (на оригинал и на копию). Оправдано ли это и как вообще делается в файловых системах? МОМЕНТ 2 Что касается отключения электричества или других проблем. Думаю что не стоит полностью полагаться на без проблемную работы компьютера, поэтому лучше бы понять как стоит восстанавливать данные. Выше я указал статью про FAT. Там написано как записывать файл, как удалять, перемещать, копировать. Но там ничего не написано про возникающие ситуации (про ошибки). Если рассмотреть удаление, то это нужно пометить элемент в списке папки как удалённый, пройтись по цепочке кластеров, на которые он указывает (точнее на начало кластера цепочки он указывает), и обнулить их. Так с чего начать нужно? Если сначала начать обнулять кластера (не сами кластера, а именно описания кластеров) и вдруг в этот момент отключили электричество, то получится классная вещь: файл существует, занимает размер (или не занимает если папка), а кластеры, на которые он указывает содержат 0x00 (точнее описания кластеров). Данные пропали! А если сначала помечать объект в списке как удалённый и вдруг отключили питание. Тогда объект из списка мы потеряли, но и потеряли кластеры, так как они в списке кластеров навечно остались занятыми (конечно если не запускать специальную утилиту, которая будет искать для начала цепочки файла указывающий на неё файл). Получается что везде не хорошо. Так как тогда себя обезопасить от такой операции? Ведь удаление - это ещё цветочки, хотя и оно подразумевает обширную программу, если удалять папку, в которой есть файлы и папки. Тогда нужно будет проходиться по каждому элементу и очищать его не только из списка, но и из характеристики кластеров. А вдруг при 346 файле из 700 произойдёт отключение питания. Что тогда? Как восстановить? Я уже боюсь думать про такие зверские операции, как запись данных в файл (файл увеличивается или уменьшается - одним словом, меняется). Тут у меня даже фантазия не включается как сделать. Другое дело переименование - тут просто изменить то, что лежит в секторе. Да, кстати, если сделать что кластер будет не 1 сектор, а больше, то возможна и ошибка в таком случае, что только половина кластера была записана при отключении питания. Даже простое перемещение требует как минимум два раза записи (откуда и куда). А если все эти операции делать с учётом копий, то вообще чекануться можно. Журналирование, журналирование... а как им реализовать всё это? Выделить область для журнала (надеюсь журнал дублировать не нужно будет) и писать там то, что собираешься сделать, и если сделал, то уже отметку затираешь. Но по сути что туда писать? Что писать при переименовании итак понятно, если делать её и для дублирования: какой объект был, какой нужен и далее вносить записи в журнал, переименовали ли в оригинале, переименовали ли в копии. При перемещении что-то наподобие. При удалении чёрт знает что туда вносить. А при записи в файл, у меня вообще мозги отказывают соображать. Не писать же мне в журнале те данные, которые я хочу добавить в файл, с какой позиции и прочее... В общем у меня сейчас бурно играет фантазия. Если кто-то может, дайте дельный урок - объясните по пальцам.
Всем доброго утра! Хотелось бы у Вас спросить по поводу фрагментации и дефрагментации. В моём понимании, фрагментация - это не когда между объектами есть свободное место. А когда объекты разделены на кластеры, путь к которым проходит через другие кластеры. Процесс дефрагментации позволяет собрать кластеры объекта в одном месте. Но мне интересно, как же программа дефрагментации производит эти манипуляции. Как осуществляется дефрагментация в FAT? Про NTFS даже думать не хочу, тем более что сколько не пытался в Windows 7 выполнить дефрагментацию, она оказывалась всегда не нужной. Такое ощущение, что Windows 7 дефрагментацию сам выполняет в фоновом режиме когда ему это нужно. Просто дефрагментацию - это перемещение кластеров в другое место, то есть копирование. А для копирования нужно чтобы место свободное уже было. Ведь так придётся уже какой-то кластер копировать в резервный кластер, кластер где он был раньше очищать и на его место копировать данные другого кластера. И при этом нужно переуказывать индексы следующих кластеров в цепочках и переуказывать индексы кластеров начала цепочек в самих записях объектов. Тут уже если произойдёт сбой, будет не поправимое (по крайней мере для FAT, как мне кажется). Может кто-нибудь рассказать как производится дефрагментация?
Всем доброго дня! Не стал я использовать FAT12, а решил написать своё подобие. Сейчас реализовываю менеджер для работы с образами SFS12. Если кому интересно, то предлагаю содержимое файла с объявлениями структур: Code (Text): #pragma once #include <memory> #define SFS12_BOOT_SECTOR_IDENTIFIER "SFS12\0" #define SFS12_BOOT_SECTOR_SIGNATURE 0xAA55 #define SFS12_BOOT_SECTOR_SIGNATURE_BYTE1 0x55 #define SFS12_BOOT_SECTOR_SIGNATURE_BYTE2 0xAA #define SFS12_CLUSTERS_LIST_FREE 0x0000 #define SFS12_CLUSTERS_LIST_ERROR 0x0FF6 #define SFS12_CLUSTERS_LIST_END_CHAIN_BOOT 0x0FF7 #define SFS12_CLUSTERS_LIST_END_CHAIN_RESERVED 0x0FF8 #define SFS12_CLUSTERS_LIST_END_CHAIN_CLUSTERS_LIST 0x0FF9 #define SFS12_CLUSTERS_LIST_END_CHAIN_COPY_CLUSTERS_LIST 0x0FFA #define SFS12_CLUSTERS_LIST_END_CHAIN_ROOT_DIRECTORY 0x0FFB #define SFS12_CLUSTERS_LIST_END_CHAIN_ROOT_DIRECTORY_ITEMS 0x0FFC #define SFS12_CLUSTERS_LIST_END_CHAIN_DIRECTORY 0x0FFD #define SFS12_CLUSTERS_LIST_END_CHAIN_DIRECTORY_ITEMS 0x0FFE #define SFS12_CLUSTERS_LIST_END_CHAIN_FILE 0x0FFF #define SFS12_OBJECT_DESCRIPTION_STATUS_FREE 0 #define SFS12_OBJECT_DESCRIPTION_STATUS_OBJECT 1 #define SFS12_OBJECT_DESCRIPTION_INDEX_PARENT_ROOT_DIRECTORY 0 #pragma pack(1) struct SFS12_BootSector { char jmpCode[3]; char identifier[8]; char description[12]; unsigned char cylinders; unsigned char tracksInCylinder; unsigned char sectorsInTrack; unsigned short int bytesInSector; unsigned char sectorsInCluster; unsigned short int indexReserved; unsigned short int indexClusters; unsigned short int indexCopyClusters; unsigned short int indexRootDirectory; unsigned char unfinishedAction; char code[472]; char signature[2]; }; #pragma pack() #pragma pack(1) struct SFS12_ObjectDescription { unsigned char status; unsigned short int indexParent; char name[24]; char expansion[4]; unsigned char attributes; unsigned int size; char createDate[4]; char createTime[4]; char readDate[4]; char readTime[4]; char writeDate[4]; char writeTime[4]; unsigned short int indexData; unsigned short int items; }; #pragma pack() union SFS12_Union_UShortToChars { unsigned short int value; char bytes[2]; }; unsigned int SFS12_GetTextLength(const char* _src); unsigned int SFS12_GetTextLength(const char* _src,const unsigned int _maxLength); bool SFS12_SetText(char* _dsc,const unsigned int _dscLength,const char* _src); bool SFS12_SetText(char* _dsc,const unsigned int _dscLength,const char* _src,const unsigned int _srcLength); bool SFS12_SetDate(char* _dsc,const unsigned char _day,const unsigned char _month,const unsigned short int _year); bool SFS12_SetTime(char* _dsc,const unsigned char _hour,const unsigned char _minute,const unsigned char _second); bool SFS12_ClearCluster(char* _data,const unsigned short int _sectorsInCluster,const unsigned short int _indexCluster); bool SFS12_ClearClusters(char* _data,const unsigned short int _sectorsInCluster,const unsigned short int _indexCluster,const unsigned short int _clustersCount); bool SFS12_SetCluster(char* _data,const unsigned short int _sectorsInCluster,const unsigned short int _indexCluster,const char* _cluster); bool SFS12_SetClusters(char* _data,const unsigned short int _sectorsInCluster,const unsigned short int _indexCluster,const unsigned short int _clustersCount,const char* _clusters); bool SFS12_SetNotFullCluster(char* _data,const unsigned short int _sectorsInCluster,const unsigned short int _indexCluster,const char* _clusterPart,const unsigned short int _clusterPartSize); bool SFS12_SetNotFullClusters(char* _data,const unsigned short int _sectorsInCluster,const unsigned short int _indexCluster,const unsigned short int _clustersCount,const char* _clusters,const unsigned short int _clusterPartSize); bool SFS12_GetCluster(char* _cluster,const unsigned short int _sectorsInCluster,const char* _data,const unsigned short int _indexCluster); bool SFS12_GetClusters(char* _clusters,const unsigned short int _clustersCount,const unsigned short int _sectorsInCluster,const char* _data,const unsigned short int _indexCluster);
Я сейчас сделал так, что у меня есть структура BootSector (собственно она всегда и везде есть). В ней информация о дискете (количество цилиндров, дорожек на цилиндре, секторов на дорожке и байтов в секторе) и информация о файловой системе (идентификатор, описание, количество секторов в кластере, где начинаются резервные кластера, где начинается описание кластеров, где начинается (если она вообще есть) копия описания кластеров, где начинается корневая папка и статус последнего действия). Вот как она выглядела бы на ассемблере: Code (Text): jmpCode db 0x00,0x00,0x00 identifier db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 description db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 cylinders db 0x00 tracksInCylinder db 0x00 sectorsInTrack db 0x00 bytesInSector dw 0x0000 sectorsInCluster db 0x00 indexReserved dw 0x0000 indexClusters dw 0x0000 indexCopyClusters dw 0x0000 indexRootDirectory dw 0x0000 unfinishedAction db 0x00 code db ; Тут код загрузочного сектора на 472 байта signature db 0x00,0x00 Описания кластеров - это двух байтный массив, элемент которого кое-что характеризует. Характеристика следующая: 0x0000 - кластер свободен 0x0FF7 - кластер с ошибкой 0x0FF8 - кластер с загрузочным сектором 0x0FF9 - последний кластер цепочки резервных кластеров 0x0FFA - последний кластер цепочки характеристики кластеров 0x0FFB - последний кластер цепочки копии характеристики кластеров 0x0FFC - кластер с корневой директорией 0x0FFD - последний кластер цепочки элементов корневой папки 0x0FFE - последний кластер цепочки элементов папки 0x0FFF - последний кластер цепочки данных файла Значение в диапазоне от 0x0001 до 0x0B3F означают индекс кластера. Значения в диапазоне от 0x0B40 до 0x0FF6 и от 0x1000 до 0xFFFF запрещены! И есть структура ObjectDescription где содержится описание объекта (папки/файла). Там указывается индекс кластера, где лежит список описаний объектов, среди которого есть и описание папки, к которой принадлежит данный объект. Если в качестве индекса родительского объекта стоит значение 0x0000, то данный объект лежит в корневой папке. Ну и дальше обычные поля для описания объекта. Ничего тут особенного нет. Единственное, что есть специальное поле status, которое говорит о том, удалён ли объект или нет из списка. То есть в FAT для этого использовался первый символ в имени, а у меня отдельное поле. Вот как она выглядела бы на ассемблере: Code (Text): status db 0x00 indexParent dw 0x0000 name db ; Тут имя объекта на 24 байта expansion db 0x00,0x00,0x00,0x00 attributes db 0x00 size dd 0x00000000 createDate db 0x00,0x00,0x00,0x00 createTime db 0x00,0x00,0x00,0x00 readDate db 0x00,0x00,0x00,0x00 readTime db 0x00,0x00,0x00,0x00 writeDate db 0x00,0x00,0x00,0x00 writeTime db 0x00,0x00,0x00,0x00 indexData dw 0x0000 items dw 0x0000 В общем так вот всё и устроено. Сейчас для неё пишу программу, чтобы можно было создавать образ, создавать в нём папки и испортировать в них файлы. И что, разве плохая файловая система?