Конференция "WinAPI" » Как удалить файл без восстановления [D7]
 
  • nikfel (22.03.08 11:03) [0]
    Подскажите, пожалуйста. Как удалить файл со всем, чтобы восстановить было нельзя. Заранее спасибо.
  • Ega23 © (22.03.08 11:11) [1]
    Затереть нулями кластеры, занимаемые файлом.
  • tesseract © (22.03.08 12:39) [2]

    > Затереть нулями кластеры, занимаемые файлом.


    Можно без кластеров. Если размер файла не меняеться, то перезапись его содержимого не вызовет перераспределение кластеров на которых  файл находиться.
  • guav © (22.03.08 14:02) [3]
    В общем случае сложный вопрос, есть случаи, когда [1] и [2] не сработают.
    Особенно сложно, если нужно стереть ещё имя файла.знать о том что файл должен быть потом стёрт совсем уже при создании файла.
  • ЦУП © (22.03.08 14:10) [4]

    > В общем случае сложный вопрос, есть случаи, когда [1] и
    > [2] не сработают.


    А что это за случаи?
  • guav © (22.03.08 14:43) [5]
    > [4] ЦУП ©   (22.03.08 14:10)

    На NTFS нет строгого соотвествия между данными в файле и данными в его кластерах.
    Например сжатый файл займёт кластеров меньше чем его размер, тут [2] может не сработать.
    Если файл который полностью поместился в MFT, то при перезаписи методом [1] будет повреждена файловая система, при этом файл моет остатьсыя восстановимым. А при перезаписи методом [2] будет востановим. Тут Rouse_ давал ссылку на книгу "Криминалистический анализ файловых систем", там эти тонкости NTFS.

    Ну и что уже применимо к любой ФС, следы файла могут быть во всяких темпах, кэшах и свопах. И, при дефрагментации, в старом расположении файла. И ещё есть флешки которые менят маппигн секторов на их физическу память, чтобы распределить "износ" флешки равномерно, тогда затираемый кластер может не совпасть с кластером файла.
  • guav © (22.03.08 14:48) [6]
    Есть подозрение, что на NTFS поможет FSCTL_SET_ZERO_ON_DEALLOCATION, если указывать сразу при создании, не проверял. Но требует Vista.
  • TStas © (22.03.08 16:56) [7]
    А почему нельзя получить размер файла, если он > 0, открыть его в режиме Чтение/запись и перезаписать нулями? Размер не изменится, а в файле одни нули будут. А потом просто deleteFile ему сделать. Вот и удаление без восстановления.
  • Riply © (22.03.08 17:21) [8]
    > [7] TStas ©   (22.03.08 16:56)
    > А почему нельзя получить размер файла, если он > 0, открыть его в режиме
    > Чтение/запись и перезаписать нулями? Размер не изменится, а в файле одни нули будут.
    > А потом просто deleteFile ему сделать. Вот и удаление без восстановления.

    А кто тебе сказал, что "перезаписываемые нули" будут перезаписываться именно
    в теже кластеры, где располагался файл ? (Sorry за тавтологию :)
    Более того, если файл, например, исходно был фрагментирован, то шансов для этого
    становится очень мало.
  • guav © (22.03.08 19:34) [9]
    > [7] TStas ©   (22.03.08 16:56)

    Уже предложено в [2]. Не будет это работать для всех файлов.
    Более того писать именно нулями - идея более плохая чем писать случайными даными, если файл сжат, то "запись" почти ничего не сделает.
  • Игорь Шевченко © (22.03.08 22:13) [10]
    Riply ©   (22.03.08 17:21) [8]


    > Более того, если файл, например, исходно был фрагментирован,
    >  то шансов для этого
    > становится очень мало.


    Ты хочешь сказать, что при записи в файл он дефрагментируется ?

    guav ©   (22.03.08 19:34) [9]


    > Более того писать именно нулями - идея более плохая чем
    > писать случайными даными, если файл сжат, то "запись" почти
    > ничего не сделает.


    Запись как бы скорректирует кластеры, занимаемые файлом, нет ?
    Или тв хочешь сказать, что зная кластер на диске, ты гарантировано скажешь, какому файлу он принадлежал в прошлом ?
  • Riply © (22.03.08 22:42) [11]
    >  [10] Игорь Шевченко ©   (22.03.08 22:13)
    > Ты хочешь сказать, что при записи в файл он дефрагментируется ?

    Нет, конечно. Точнее: не такое строгое утверждение.
    Но я неоднакратно наблюдала ( и воспроизводила) дефрагментацию файла при записи.
  • Riply © (22.03.08 22:53) [12]
    > [11] Riply ©   (22.03.08 22:42)
    > Но я неоднакратно наблюдала ( и воспроизводила) дефрагментацию файла при записи.

    Имеется ввиду на NTFS
  • Игорь Шевченко © (22.03.08 22:58) [13]
    Riply ©   (22.03.08 22:42) [11]

    Ничего не понимаю - есть файл, у него есть N кластеров. Содержимое файла аккуратно заполняется произвольными данными (хотя бы и нулями).

    Он имеет возможность стать дефрагментированым ?
  • Riply © (22.03.08 23:07) [14]
    > [13] Игорь Шевченко ©   (22.03.08 22:58)
    > Ничего не понимаю - есть файл, у него есть N кластеров.
    > Содержимое файла аккуратно заполняется произвольными данными (хотя бы и нулями).
    > Он имеет возможность стать дефрагментированым ?

    Да.
    Я воспроизводила, примерно, такое:
    Создавала файл, например, занимающий восемь кластеров с "номерами":
    0..3,  128...131.
    И после "обычной" записи в него его картинка становилась: 0..7.
    Я не утверждаю, что это происходит всегда,
    но в моих тестах это повторилось несколько раз.
  • Riply © (22.03.08 23:10) [15]
    С заполнением нулями сжатого или разряженного файла, вообще интересно.
    Такое впечатление (может и неправильное),
    что система может вызвать FSCTL_SET_ZERO_DATA, если ей заблагорассудится :)
    А FSCTL_SET_ZERO_DATA может не вести "реальной" записи на диск, а только "подправить" MFT :)
  • Игорь Шевченко © (23.03.08 00:23) [16]
    Riply ©   (22.03.08 23:07) [14]

    Пример в студию. Атрибуты файла, как открывала, как писала, расположение кластеров до, расположение кластеров после.
    Или ссылки, подтверждающие подобные случаи и/или поведение.

    До того момента не верю.
  • guav © (23.03.08 00:42) [17]
    > [10] Игорь Шевченко ©   (22.03.08 22:13)
    > Запись как бы скорректирует кластеры, занимаемые файлом,
    > нет ?
    > Или тв хочешь сказать, что зная кластер на диске, ты гарантировано
    > скажешь, какому файлу он принадлежал в прошлом ?

    Даже если считать что достаточно разрыва связи между файлом и его данными, в NTFS обновления Data Runs всегда журналируются, поэтому, возможно, связь не будет безнадёжно утеряна в этом случае.
    Обычно от надёжного удаления файла хотят преде всего невостановимость самих данных, а не уничтожения информации о файле.
  • Игорь Шевченко © (23.03.08 00:49) [18]
    guav ©   (23.03.08 00:42) [17]


    > в NTFS обновления Data Runs всегда журналируются


    И живут там вечно ? Мне просто интересно
  • guav © (23.03.08 01:22) [19]
    > [18] Игорь Шевченко ©   (23.03.08 00:49)

    Нет. Но часто живут там достаточно долго.
    Логфайл состоит из циклического буфера страниц, т.е. всегда перезаписыватся самые старые.
    В NT запись начинается сначала при каждом монтировании, в более новых (2000 и новее) цикл не обрывается и при монтировании/демонтировании.
  • Игорь Шевченко © (23.03.08 02:17) [20]
    guav ©   (23.03.08 01:22) [19]

    Век живи, век учись. Примерчик можно ?
  • Riply © (23.03.08 02:18) [21]
    > [16] Игорь Шевченко © (23.03.08 00:23)
    > Пример в студию. Атрибуты файла, как открывала, как писала,
    > расположение кластеров до, расположение кластеров после.
    > Или ссылки, подтверждающие подобные случаи и/или поведение.

    Ссылок разумеется нет, впрочем как и нормальной документации по NTFS.
    Соответственно попытка изучить это безобразие(NTFS), в основном, строится на тестах
    и изучении их результатов. Их приходиться проводить очень много.
    И разумеется, у меня не сохранились ни полное описание
    условий, при которых я получила данный результат, ни функций, написанных
    спецально для него. Я увидела, что это возможно, сделала себе пометку, "намотала на ус" и пошла дальше :)
    Но, чтобы не остаться голословной, я попробую еще раз получить условия, в которых
    это воспроизводится более-менее стабильно. Но на это потребуется время.
    Так что, придется подождать. Хорошо ?

    > До того момента не верю.
    И правильно :) Я тоже стараюсь все проверять сама :)
  • guav © (23.03.08 02:53) [22]
    > [20] Игорь Шевченко ©   (23.03.08 02:17)

    Примерчик чего ?
    Читалку логфайла дать не могу.
    Про сам логфайл можно прочитать в "Inside Windows 2000".
    Опыт подтверждающий восстановимость резидентных файлов через логфайл описан в книге "Криминалистический анализ файловых систем" (там не учтена разбивка логфайла на страницы и необходимость восстановления двух последних байт каждого сектора кадой страницы, но при достаточном везении эти два фактора могут не повлиять и даные будут байт-в-байт как и были). Опыт подтверждащий восстановимость датаранов будет аналогичным. Просто создаём, меняем, ищем в логфайле старый и новый варианты и находим.
  • guav © (23.03.08 15:29) [23]
    http://www.osronline.com/showThread.cfm?link=54720
    Вот интересная ссылка по теме, там автор тоже озабочен удалением и, видимо, не нашел способа "борьбы" с журналированием.
  • Игорь Шевченко © (23.03.08 17:00) [24]
    там автор озабочен удалением мелких файлов :)
  • guav © (23.03.08 17:25) [25]
    > [24] Игорь Шевченко ©   (23.03.08 17:00)

    Ну так датараны "крупных" так же журналируются, как и данные "мелких", даже более тщательно (данные резидентных файлов в некоторых случаях не попадают в логфайл, а датараны нерезидентных - всегда попадают).
  • Denis__ © (23.03.08 18:39) [26]
    самый простой способ удалить файл так, чтобы его нельзя было восстановить - просерлить жестак и залить пузырёк кислоты внутрь.А потом ещё молоточком пройтись, сверху:) (с) С.Лукьяненко.
  • Игорь Шевченко © (23.03.08 19:12) [27]
    guav ©   (23.03.08 17:25) [25]

    Минуточку - там же написано, что после контрольной точки они как бы становятся ненужными. Я вот честно не слышал, что в NTFS ведется хронология изменений файла...

    Впрочем, сам понимаешь, достаточно хорошенько переписать соседние файлы и лог забьется...
  • guav © (23.03.08 19:37) [28]
    > [27] Игорь Шевченко ©   (23.03.08 19:12)
    > Минуточку - там же написано, что после контрольной точки
    > они как бы становятся ненужными.

    Становятся ненужными - да, большинство записей становятся ненужными после контрольной точки. Но не затираются.


    > Я вот честно не слышал, что в NTFS ведется хронология изменений
    > файла...

    И это есть, USN Log, но это опция, на ХР по дефолту выключена, и пишет только события, но не данные.

    Данные действительно специально не журналируются. В логфайле журналируются метаданные, т.е. из нерезиднетных файлов туда специально пишутся только данные метафайлов.


    > Впрочем, сам понимаешь, достаточно хорошенько переписать
    > соседние файлы и лог забьется...

    Да. Но если хорошенько переписать. И желательно знать, как переписывать, чтобы побыстрее его забить.
    Я смотрел некоторые "стиралки", которые затирают неиспользованые MFT записи и свободное место тома, они таки затирают это всё, но в результате обработки ими тома в логфайле обычно появляется слишком мало записей, чтобы затереть значительную часть логфайла.
  • guav © (23.03.08 19:42) [29]
    Я в [3] наверное плохо сформулировал свою точку зрения, повторюсь:
    Если нужна возможность надёжно удалить файл, то об этом надо думать уже при создании файла. Перед удалением сложнее обеспечить надёжное удаление, а после обычного удаления - ещё сложнее.
  • Игорь Шевченко © (23.03.08 20:44) [30]
    guav ©   (23.03.08 19:37) [28]

    Кстати. Насколько я понимаю, все это журналирование ведется на предмет восстановления после сбоев, а не из любви к искусству. В противном случае диск бы сразу был забит лог-файлом при достаточно интенсивной работе с файлами. Например, с pagefile.sys :))
  • guav © (23.03.08 21:01) [31]
    > [30] Игорь Шевченко ©   (23.03.08 20:44)

    Именно так, и действительно в случаях вроде pagefile.sys туда ничего не попадает.

    Журналирование "из любви к искусству", т.е. не нужное для работы самой ФС - это USN Journal, см. http://msdn2.microsoft.com/en-us/library/aa363801.aspx
  • guav © (23.03.08 21:04) [32]
    > диск бы сразу был забит лог-файлом

    Кстати диск не может быть забит логфайлом, размер логфайла вообще не увеличивается, он цикличен. Да, есть проблема, что логфайл может "наступить себе на хвост", но она обрабатывается.
  • Игорь Шевченко © (23.03.08 23:23) [33]
    guav ©   (23.03.08 21:04) [32]

    Я все о другом - о том, что следы в нем недолго хранятся. И использовать его как средство доступа к удаленной информации, занятие, на мой взгляд, малоперспективное.

    Кстати: "the NTFS file system maintains a change journal. When any change is made to a file or directory in a volume, the change journal for that volume is updated with a description of the change and the name of the file or directory"

    Насколько я понял, старых данных там не хранится...
  • guav © (24.03.08 02:34) [34]
    > [33] Игорь Шевченко ©   (23.03.08 23:23)
    > Я все о другом - о том, что следы в нем недолго хранятся.
    > И использовать его как средство доступа к удаленной информации,
    > занятие, на мой взгляд, малоперспективное.

    Возражать не буду, лучше расскажу как посчитать сколько в среднем хранится записи.
    Читаем в логфайле DWORD по смещению 0x40. Будет где-то между 0x20 и 0x30. Отнимаем от 0x40 прочитанное. Получится значение, на которое надо сдвинуть вправо LSN, чтобы получить номер перезаписи файла. Создаём файл и смотрим его LSN, сдвигаем его на вычисленную константу, получим число равное номеру цикла перезаписи логфайла. Теперь вычитаем из даты того файла дату логфайла, мы получаем время существования тома. Разделив это время на число циклов перезаписи, получим, сколько в среднем живёт запись логфайла. Для всего этого можно взять MFT_Scan, который by Riply :-) (LSN там назван _Usn64)
    Понятно, что это время зависит от того системный ли диск, включено ли обновление времени последнего доступа, и т.п. и может получится и меньше дня и больше месяца.


    > Кстати: "the NTFS file system maintains a change journal.
    > When any change is made to a file or directory in a volume,
    > the change journal for that volume is updated with a description
    > of the change and the name of the file or directory"
    >
    > Насколько я понял, старых данных там не хранится...

    Здесь речь скорее идёт об USN Journal ($UsnJrnl) а не о логфайле ($LogFile).

    В $LogFile тарые данные хранятся для отмены незавершенной операции (в "Inside Windows 2000" это названо "undo pass"), новые хранятся для возможности повтора операции ("redo pass"). Кроме случаев, когда операция - отмена или повтор по логфайлу, для кадой операции хранятся и данные для повтора и данные для отмены.
  • guav © (24.03.08 02:50) [35]
    > [33] Игорь Шевченко ©   (23.03.08 23:23)
    > Кстати: "the NTFS file system maintains a change journal.

    Ну да, это по ссылке из [31]. Change Journal не имеет (почти) отношения к Log File.
    Про логфайл в MSDN мало пишут, немного есть тут http://support.microsoft.com/kb/101670
  • Игорь Шевченко © (24.03.08 09:41) [36]
    guav ©   (24.03.08 02:34) [34]

    Это все хорошо, но вот тот же Руссинович пишет, что журналируются метаданные, то есть, элементы каталогов и прочая..
    Насчет данных самого файла - мне бы все-таки хотелось пример получить, как из перезаписанного файла на NTFS получить старые данные.

    Нетрудно будет набросать ?
  • guav © (24.03.08 11:00) [37]
    > [36] Игорь Шевченко ©   (24.03.08 09:41)

    К метаданным про которые пишет Руссинович (кстати он ли ? в книге "Inside Windows NT", автор которой не Руссинович, про журналирование написано в точности то же самое, что в "Inside Windows 2000") относятся все метаданные. Включая всё, что пишется в MFT.

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

    Данные пользовательских нерезидентных файлов не попадают в логфайл, но датараны (пары логическийКластер-количествоКластеров) попадают, т.е. дают утвердительный ответ на [10] для прошлого в пределах времени цикла логфайла. Т.е. если действительно затереть их кластеры, то данные не будут восстановимы через логфайл, но если применить совет [7] к сжатому файлу, то могут быть (получится то, про что пишет Riply в [15] и никакого реального затирания кластеров не будет).

    Кода не будет, потому что NDA.
  • Игорь Шевченко © (24.03.08 11:16) [38]

    > Т.е. если действительно затереть их кластеры, то данные
    > не будут восстановимы через логфайл


    Собственно, в чем были уверены большевики. Спасибо.
  • guav © (24.03.08 11:36) [39]
    > [38] Игорь Шевченко ©   (24.03.08 11:16)

    Только могут быть и другие уязвимости, не связанные с NTFS.

    Ну и есть удалялки, использующие удаление путём повторной записи в файл, так они могут перезаписать не те кластеры.
    (простой способ воспроизвести [14] - пробовать на сжатом файле).
  • guav © (24.03.08 11:42) [40]
    > [39] guav ©   (24.03.08 11:36)
    > (простой способ воспроизвести [14] - пробовать на сжатом файле).

    Сейчас что-то не получается просто сжать и изменять, чтобы файл "переехал". Но явление тоже наблюдал.
  • Riply © (24.03.08 15:09) [41]
    > [40] guav ©   (24.03.08 11:42)
    > Сейчас что-то не получается просто сжать и изменять, чтобы файл "переехал".
    > Но явление тоже наблюдал.

    Я уже написала процедуру, рекурсивно создающую дамп Run - ов всех объектов,
    содержащихся в директории вместе с их именами и LCN - ми.
    Осталось реализовать сравнение дампов,
    и можно будет "во всеоружии" приступить к поимке переезжающих файлов :)
  • Игорь Шевченко © (25.03.08 09:52) [42]
    Riply ©   (24.03.08 15:09) [41]

    "Я нашел,  как применить здесь нестирающиеся шины  из  полиструктурного  волокна  с  вырожденными аминными  связями и неполными кислородными группами.  Но я не знаю пока, как использовать регенерирующий реактор на субтепловых нейтронах.  Миша, Мишок!  Как быть с реактором?"
    (с) А и Б Стругацкие
  • Riply © (25.03.08 09:52) [43]
    Мне не удалось воспроизвести "переезд" кластеров файла,
    как прямое следствие записи в него.
    Это означает только недостаточность моих знаний, но никак
    не то, что данный "переезд" невозможен.
    Уж не говоря о том, что не поймала сегодня - поймаю завтра :)
    Повторюсь: эффект, я наблюдала и не раз.
    Тогда он мне был совсем не нужен.
    Я рассматривала возможности "безопасной прямой записи" данных в файл.
    И то, что мне удалось зафиксировать "переезд"
    ставило крест на моем способе "блокировки класеров".
    Помню, расстроилась тогда :)

    Зато мне удалось написать легко воспроизводимый пример,
    доказывающий, что при обычной записи в файл,
    никакой гарантии, что мы пишем в нужные кластеры нет :)

    Я приведу только схему кода, т.к. в нем используется очень много
    "самолапных" функций и классов (очень лень выдергивать все это. Sorry),
    но попробую прокоментировать происходящее.
    Приступим:
    function ReadWippedFile(const pSourName: PUNICODE_STRING): NTSTATUS;
    const
    StuffExt: WideString = '.stuff';
    sHelloDolly: WideString = 'Hello Dolly !!!' + sLineBreak + 'Wipped file: ';
    var
    SourLcn, StuffLcn: _LCN;
    StuffName: UNICODE_STRING;
    MFTDisk: TMFTScan;
    hFileObj: THandle;
    pBuffer: Pointer;
    BufferSize, SourceClustersCount, StuffClustersCount: DWord;
    begin
    StuffLcn := -1;
    SourLcn := -1;
    SourceClustersCount := 4;
    StuffClustersCount := SourceClustersCount * 2;
    RtlInitUnicodeString(@StuffName, PWideChar(pSourName.Buffer + StuffExt));
    // Создаем тестовый файл и временный файл, в который будем перемещать класеры.
    // Задаем им размеры.
    Result := Nt_FileCreateSized(pSourName, SourceClustersCount * BytesPerCluster, SET_SIZE_FLAG_INSTANCE, nil);
    if NT_SUCCESS(Result) then Result := Nt_FileCreateSized(@StuffName, StuffClustersCount * BytesPerCluster, SET_SIZE_FLAG_INSTANCE, nil);
    if NT_SUCCESS(Result) then
     begin
      MFTDisk := TMFTScan.Create;
      try // TMFTScan - класс для работы с диском
       Result := MFTDisk._Set_CallBackFunctions(pSourName, nil); // настраиваем
       if Result = STATUS_SUCCESS then Result := MFTDisk.NtGetObjectRetrievalPointers(@StuffName, 0);
       if Result = STATUS_SUCCESS then
        begin // получили RetrievalPointers. Проверяем их пригодность как буфера для перемещения
         with PRETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData)^ do
          if ExtentCount > 0 then
           with Extents[0] do
            if (Lcn.QuadPart > 0) and (NextVcn.QuadPart >= SourceClustersCount)
             then StuffLcn := Extents[0].Lcn.QuadPart;
         if StuffLcn <= 0 then
          begin
           ShowMessage('Stuff file is fragmented. Try again' + sLineBreak
                       + Pars_RETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData));
           Exit;
          end
         else Nt_DeleteFileU(@StuffName, 0);
         Result := MFTDisk.NtGetObjectRetrievalPointers(pSourName, 0);
         if Result = STATUS_SUCCESS then
          begin // Запоминаем исходные RetrievalPointers нашего файла и записываем их в лог
           with PRETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData)^ do
           if ExtentCount > 0 then SourLcn := Extents[0].Lcn.QuadPart;
           Log_WriteStatusNT('Try to move to: ' + IntToStr(StuffLcn) + sLineBreak
                             + Pars_RETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData), Result);
          end;
         // Подготовка закончена, приступаем к работе
         if Result = STATUS_SUCCESS then
          begin // Открываем наш файл
           Result := Nt_OpenFile(pSourName, FILE_WRITE_DATA or SYNCHRONIZE, FILE_SHARE_ALX_NONE,
                                 FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, nil, nil, hFileObj);
           if Result = STATUS_SUCCESS then
            try
             BufferSize := SourceClustersCount * BytesPerCluster;
             pBuffer := GetMemory(BufferSize);
             if pBuffer <> nil then
              try
               Записываем в буфер приветствие для Dolly и имя файла.
               FillBuffer(pBuffer, BufferSize, sHelloDolly + sLineBreakW + pSourName.Buffer);
               Result := Nt_WriteFile(hFileObj, pBuffer, BufferSize, nil);
               FlushFileBuffers(hFileObj);
               // Записали данные в файл, приступаем к их уничтожению
               NT_SUCCESS_SET_WORST(Result, Nt_SetFilePointer(hFileObj, nil, nil));
               if NT_SUCCESS(Result) then
                begin
                 FillChar(pBuffer^, BufferSize, 0); // Очистили буфер и записали первую половину файла
                 Result := Nt_WriteFile(hFileObj, pBuffer, BufferSize div 2, nil);
                 if Result = STATUS_SUCCESS then
                  begin
                   // Перемещаем кластеры нашего файла, записываем в лог новое расположение
                   Result := MFTDisk.MoveObjectClusters(pSourName, StuffLcn);
                   if NT_SUCCESS_SET_WORST(Result, MFTDisk.NtGetObjectRetrievalPointers(pSourName, 0))
                    then Log_WriteMessage(Pars_RETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData));
                   // и затираем вторую половину файла
                   NT_SUCCESS_SET_WORST(Result, Nt_WriteFile(hFileObj, IncPtr(pBuffer, BufferSize div 2), BufferSize div 2, nil));
                  end;
                 FillChar(pBuffer^, BufferSize, 0);
                 // читаем старые сектора нашего файла (прямое чтение)
                 Result := MFTDisk.ReadClustersToBuffer(pBuffer, SourLcn, SourceClustersCount);
                 if Result = STATUS_SUCCESS // и сохраняем их в др. файл
                  then Result := Nt_CreateFileData(@StuffName, pBuffer, BufferSize, nil, nil);
                end;
              finally
               FreeMem(pBuffer);
              end
             else Result := STATUS_INSUFFICIENT_RESOURCES;
            finally
             NT_SUCCESS_SET_WORST(Result, NtClose(hFileObj));
            end;
          end;
        end;
      finally
       MFTDisk.Free;
      end;
     end;
    end;


    Читаем лог:
    Try to move to: 623215
    ExtentCount 1
    Index 0 Lcn 1778061 Count 4
    The operation completed successfully
    ExtentCount 1
    Index 0 Lcn 623215 Count 4
    The operation completed successfully

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

    Смотрим данные, полученные прямым чтением старых секторов:
    H e l l o   D o l l y   ! ! !
    W i p p e d   f i l e :  
    \ ? ? \ I : \ Z _ S c a n T e s t D i r \ S o u r c e \ C l u s t e r e d F i l e . t x t
    (Привожу только кусок, на самом деле считано все полностью). В новых кластерах, разумеется нули :)

    P.S.
    Операции затирания, прямого чтения и перемещения можно "тасовать" как угодно
    (разумеется не нарушая логики). Результат остается тем же.

    P.P.S.
    Пример собирался "на коленке" так что строго не судите :)
    Если возникнет необходимость - напишу нормальный (пригодный для компиляции).
    Но очень лень этим заниматься. :)
  • Riply © (25.03.08 10:03) [44]
    > [43] Riply ©   (25.03.08 09:52)

    Несколько добавлений:
    Как видно из примера для перемещения кластеров не использовался Handle файла.
    MoveObjectClusters(pSourName, StuffLcn);
    Это было сделано для того, чтобы показать, что "монопольное" открытие, тоже не спасает.
    Перемещались кластеры "законными" методами с помощью FSCTL_MOVE_FILE
  • WipeInfo (25.03.08 10:09) [45]
    Eraser
    WipeInfo
  • Игорь Шевченко © (25.03.08 10:26) [46]

    > Зато мне удалось написать легко воспроизводимый пример,
    > доказывающий, что при обычной записи в файл,
    > никакой гарантии, что мы пишем в нужные кластеры нет


    Вот же. А ошибку в примере ты уже нашла ?
  • Riply © (25.03.08 10:32) [47]
    >  [46] Игорь Шевченко ©   (25.03.08 10:26)
    > Вот же. А ошибку в примере ты уже нашла ?

    Ну вот. Как всегда :(
    Пол ночи писала это дело, уже голова плохо соображает.
    И где она (ошибка) ?
  • Riply © (25.03.08 10:52) [48]
    > [46] Игорь Шевченко ©   (25.03.08 10:26)

    Ну нельзя же так издеваться над софорумчанкой :)
    В чем эта чертова ошибка ?
  • guav © (25.03.08 11:57) [49]
    > [45] WipeInfo   (25.03.08 10:09)
    > Eraser

    Вот кстати эту тулзу смотрел (код открыт).
    На NTFS она логфайл не чистит, а на FAT имеются ошибки, которые моут привести к проче данных.
  • Игорь Шевченко © (25.03.08 11:59) [50]
    Riply ©   (25.03.08 10:52) [48]

    Ошибка в том, что при обычной записи в файл (несжатый) его кластеры автомагически не перемещаются. Ибо незачем.
  • Riply © (25.03.08 12:14) [51]
    > [50] Игорь Шевченко ©   (25.03.08 11:59)
    > Riply ©   (25.03.08 10:52) [48]
    > Ошибка в том, что при обычной записи в файл (несжатый)
    > его кластеры автомагически не перемещаются. Ибо незачем.

    К "несжатый" надо еще добавить "неразраженный", и очень вероятно "не фрагментированный" :)
    Ведь не случайно эффект я наблюдала на фрагментированных файлах.

    Насчет "незачем", я бы не была столь категорична, ибо пути системы неисповедимы. :)
    Это относиться и к сторонним программам, установленным на компьютер.
    И если кто угодно из них имеет возможность переместить наш файл, когда мы в него пишем,
    то какая здесь может быть гарантия ?
    В примере я специально использовала стандартный файл, даже не фрагментированный,
    что бы показать, что и в этом случае запись может происходить "не туда".
  • Игорь Шевченко © (25.03.08 13:03) [52]
    Riply ©   (25.03.08 12:14) [51]


    > Ведь не случайно эффект я наблюдала на фрагментированных
    > файлах.


    Воспроизводи. До тех пор, пока не воспроизвела, считается за глюк инструмента.


    > В примере я специально использовала стандартный файл, даже
    > не фрагментированный,
    > что бы показать, что и в этом случае запись может происходить
    > "не туда".


    В примере ты его параллельно дварковала, причем влэндишным способом.
  • Riply © (25.03.08 13:14) [53]
    >  [52] Игорь Шевченко ©   (25.03.08 13:03)
    > Воспроизводи. До тех пор, пока не воспроизвела, считается за глюк инструмента.

    "Ох не легкая это работа, из болота тащить бегемота." (с)
    Что ж делать, буду пытаться. Но требуется время (кроме удовольствия, еще, к сожалению, и работа существует :)

    > В примере ты его параллельно дварковала, причем влэндишным способом.
    :)
    Дык дваркование из примера можно убрать и поместить
    в другой порцесс. Просто так было легче совместить его с записью в файл :)
  • Игорь Шевченко © (25.03.08 13:17) [54]
    Давай сделаем проще:
    Ты создашь файл, стандартным образом, скопируешь файл с исходным текстов какого-нибудь твоего примера, килобайт на 10 в файл с именем a.txt.

    После этого ты его аккуратно откроешь на запись, и пропишешь от начала до конца нулями или произвольным символом.

    var
     AFile: HFILE;
     FileSize, Worker: Cardinal;
     I: Integer;
     Buffer: array[0..1023] of char;
    begin
     FillChar(Buffer, SizeOf(Buffer), 65);
     AFile := CreateFile('a.txt', GENERIC_READ or GENERIC_WRITE,
       FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
     Win32Check(AFile <> INVALID_HANDLE_VALUE);
     try
       FileSize := GetFileSize(AFile, @Worker);
       if Worker <> 0 then
         raise Exception.Create('File too large to test');
       for I := 0 to (FileSize div SizeOf(Buffer)) - 1 do
         if not WriteFile(AFile, Buffer, SizeOf(Buffer), Worker, nil)
            or (Worker <> SizeOf(Buffer)) then
         raise Exception.Create('Write failed');
       if FileSize mod SizeOf(Buffer) <> 0 then
         if not WriteFile(AFile, Buffer, FileSize mod SizeOf(Buffer), Worker,
            nil) or (Worker <> FileSize mod SizeOf(Buffer)) then
         raise Exception.Create('Write failed');
     finally
       CloseHandle(AFile);
     end;
    end;



    После этого ты любым тебе доступным инструментом восстановишь содержимое этого файла :)

    Потом то же самое с сжатым файлом и с разреженным.

    Договорились ?
  • Игорь Шевченко © (25.03.08 13:20) [55]
    В дополнение к [54]

    В параллель с файлом ты можешь делать все, что угодно. Но принцип такой, что после окончания всех процессов с файлом, ты, имея диск с NTFS, пытаешь восстановить. Разумеется, способ, когда ты заранее скопируешь кластеры, занимаемые файлом до его затирания, а потом перепишешь файл в другое место каким-либо способом, хотя бы и влэндишным, считается неспортивным.
    Да, разумеется ход процесса восстановления надо в студию, чтобы пример был воспроизводимым.
  • Riply © (25.03.08 13:28) [56]
    > [54] Игорь Шевченко ©   (25.03.08 13:17)
    > Договорились ?

    Т.е. мне надо найти условия, при которых данное затирание
    будет работать не сто процентно.
    Причем такие, что сбой в затирании был воспроизводим
    при разумном числе попыток ?

    Если я правильно поняла и мне дается время, то согласна :)
  • Игорь Шевченко © (25.03.08 13:32) [57]
    Riply ©   (25.03.08 13:28) [56]

    Тебе надо сделать

    > После этого ты любым тебе доступным инструментом восстановишь
    > содержимое этого файла


    Время разумеется не ограничено :)
  • Riply © (25.03.08 13:36) [58]
    > [57] Игорь Шевченко ©   (25.03.08 13:32)
    > После этого ты любым тебе доступным инструментом восстановишь
    > содержимое этого файла

    Может не обязательно полное содержимое, а хотя бы один сектор (ну или кластер) ?

    > Время разумеется не ограничено :)

    Ну а после этого уточнения, я полностью согласная :)
  • WipeInfo (25.03.08 14:38) [59]
    Удалено модератором
    Примечание: Offtopic
  • Riply © (26.03.08 10:54) [60]
    > [55] Игорь Шевченко © (25.03.08 13:20)
    > В параллель с файлом ты можешь делать все, что угодно.

    Могу ли я в середине цикла

    for I := 0 to (FileSize div SizeOf(Buffer)) - 1 do
    if not WriteFile(AFile, Buffer, SizeOf(Buffer), Worker, nil)
     or (Worker <> SizeOf(Buffer)) then
    raise Exception.Create('Write failed');



    вызвать из него свою процедуру ?

    Идея, примерно, такая:
    Для удобства, считаем, что на каждом шаге затирается один кластер.
    Пусть исходно файл занимал кластеры с "номерами" 0 и 1.
    Допустим, у нас в цикле только два шага.
    Проходим первый шаг (как бы запись в класер 0).

    Здесь надо симитировать, что в этот момент времени
    другой процесс(поток), например, с более высоким приоритетом,
    производит "перемещение" кластеров нашего файла в кластеры с "номерами" 1000 и 1001
    NtFsControlFile(..., FSCTL_MOVE_FILE, ...)

    Проходим второй шаг цикла (как бы запись в класер ??? ).
    Завершили затирание.

    Встает такой вопрос:
    В какие кластеры реально велась запись ?
    0, 1 или 1000, 1001 ? А может в 0, 1001 ?
    Инфомация может считаться "уничтоженной без возможности восстановления"
    только в двух случаях:
    1. Запись велась в 0, 1 и они (уже затертые) переместились в 1000 и 1001.
    2. Запись велась во все четыре кластера.
    Пример, который я приводила показывает, что в общем случае это не первый и не второй варианты.
    Да и не логичные они какие-то :)
    Во всех остальны случаях информация уничтожена не полностью - т.е. не уничтожена :)

    Я спрашиваю о "добавлении" вызова функции в процедуру затирания,
    т.к. довольно сложно из другого процесса(потока) без синхронизации поймать нужный момент :)
    Можно, конечно определять "момент такой" с помощью перехвата, но это уж очень некузяво :)
    Самый простой способ - сразу вызывать NtFsControlFile, как впрочем я и делала :)
  • Игорь Шевченко © (26.03.08 12:01) [61]

    > Могу ли я в середине цикла
    >
    > for I := 0 to (FileSize div SizeOf(Buffer)) - 1 do
    > if not WriteFile(AFile, Buffer, SizeOf(Buffer), Worker,
    > nil)
    >  or (Worker <> SizeOf(Buffer)) then
    > raise Exception.Create('Write failed');
    >
    > вызвать из него свою процедуру ?


    Нет, не можешь.


    > Здесь надо симитировать, что в этот момент времени
    > другой процесс(поток), например, с более высоким приоритетом,
    >  
    > производит "перемещение" кластеров нашего файла в кластеры
    > с "номерами" 1000 и 1001
    > NtFsControlFile(..., FSCTL_MOVE_FILE, ...)


    Ну сделай файл на 1 гигабайт и запусти другой процесс параллельно.

    Идея в том, чтобы получить данные затертого файла. Код затирания я привел, и вмешиваться в него не надо. Если без хитростей с перемещением не получится, то и браться не стоит :)
  • Riply © (26.03.08 22:04) [62]
    Вроде, удалось добиться нужного результата.
    Опишу как я действовла, чтобы получить вердикт: спортивно или нет.
    Если да и потребуется код, пригодный для компиляции, - буду писать,
    если нет, то учту замечания и буду думать дальше :)

    Все происходит на NTFS диске (не виртуальном).
    Есть исходный файл, в котором хранятся наши секретные данные
    SourName = 'BaseDataFile.txt' размером DataSize = 7786 Byte.
    Подготовка:
    Копируем SourName в VictimName - этот файл будем затирать.
    Создаем файл StuffName с размером ROUND_UP(DataSize, BytesPerCluster).
    Затираем его нулями :)
    Проверяем что он не фрагментирован и получаем "номер" его первого кластера StuffLcn.
    Это временный файл, в чьи кластеры мы будем премещать подопытного.

    Пишем две процедуры:
    Первая устанавливает hEvent, сигнализирующий, что мы готовы к работе
    и переходит к ожиданию открытия нового Handle - а.
    Мы расчитываем, что он будет открыт
    процедурой затирания от Игоря: WipeFileByShevchenko

    function WaitCreateHandle(hEvent: THandle): NTSTATUS;
    var
    OldHandleCount, HandleCount: DWord;
    //....
    begin
    Result := NtQueryInformationProcess(GetCurrentProcess, ProcessHandleCount,
                                        @OldHandleCount, SizeOf(DWord), nil);
    if SetEvent(hEvent) then
     while NT_SUCCESS(Result) do
      begin
       Result := NtQueryInformationProcess(GetCurrentProcess, ProcessHandleCount,
                                           @HandleCount, SizeOf(DWord), nil);
       if HandleCount = Succ(OldHandleCount) then Exit;
       //....
      end
    //....
    end;

    Вторая процедура у нас и будет заниматься перемещением и чтением.
    Она будет работать внутри дополнительной нити.
    Выглядит она примерно так:
    function MoveAndReadWippedFile(const pVictim, pRestore: PUNICODE_STRING; hEvent: THandle; const VictimSize: DWord): NTSTATUS;
    var
    StuffName: UNICODE_STRING;
    begin
    //....
    Result := Nt_DeleteFileU(@StuffName, 0); // уничтожаем файл - контейнер кластеров.
    if Result = STATUS_SUCCESS then
     begin
      // сигнализируем, что готовы к работе и ждем открытия подопытного файла процедурой затирания
      Result := WaitCreateHandle(hEvent);
      if NT_SUCCESS(Result) then
       begin // Дождались, начинаем работу. (т.е. затиралка уже открыла файл и вовсю его трет. :))
        Result := MoveObjectClusters(pVictim, StuffLcn);
        // MoveObjectClusters - открывает файл pVictim,
        // получает его RETRIEVAL_POINTERS_BUFFER
        // после чего, перемещает его кластеры в подготовленные нами кластеры StuffName
        // закрывает файл
        ReadRetPointersToFile(IoData.pData, pRestore, VictimSize);
        // Считывает кластеры из старого расположения нашего подопытного (прямое чтение)
        // и сохраняет данные в файл pRestore
       end;
    //....
    end;

    Процедура нити:
    function MoveClusters(pParams: Pointer): integer;
    begin
    Result := 0;
    with PMoveParams(pParams)^ do
     try
      MoveStatus := MoveAndReadWippedFile(@VictimName, @RestoreName, hMoveEvent, VictimSize)
     finally
      SetEvent(hMoveEvent);
     end;
    end;

    Ну и вызов всего этого безобразия:

    hMoveEvent := CreateEvent(nil, False, False, nil);
    if hMoveEvent <> 0 then
    try
     hThread := BeginThread(nil, 0, MoveClusters, @MoveParams, 0, ThreadID);
     if hThread <> 0 then
      try // Ждем сигнала готовности
       if WaitForSingleObject(MoveParams.hMoveEvent, 100000) = WAIT_OBJECT_0 then
        with MoveParams do
         begin
          // Вызываем затирающую процедуру
          WipeFileByShevchenko(VictimName.Buffer);

    Уфф. Вроде ничего не упустила.

    Несколько тестов показали, что
    при данных условиях, "затертые" данные восстанавливаются полностью.

    P.S.
    Понимаю некузявость кода. Он приведен толко как схема действий
    для получения вердикта о спортивности поведения :)
  • Игорь Шевченко © (26.03.08 23:03) [63]

    > WipeFileByShevchenko


    Я пишусь так: Schevchenko

    Насчет спортивности - гораздо проще скопировать файл перед его затиранием. Не надо с кластерами возиться.

    Я вроде написал свои условия. А у тебя получается, что ты копируешь кластеры, параллельно затираешь файл, а потом из скопированных читаешь.

    Неспортивно.
  • Riply © (26.03.08 23:18) [64]
    > [63] Игорь Шевченко ©   (26.03.08 23:03)
    > Я пишусь так: Schevchenko

    Sorry

    > Насчет спортивности - гораздо проще скопировать файл перед его затиранием. Не надо с кластерами возиться.

    Перед затиранием я ничего не делаю.

    > Я вроде написал свои условия.

    Я поняла так, что "В параллель с файлом ты можешь делать все, что угодно"

    >А у тебя получается, что ты копируешь кластеры, параллельно затираешь файл, а потом из скопированных читаешь.

    Нет, не так получается, а вот как: я вынуждаю функцию затирать не те кластеры, где располагался файл,
    а новые, совершенно другие. Что она с успехом и делает :)
    И считываю я не из "скопированных класеров" а из "старых", которые в результате
    остались на диске безхозными и не затертыми. :)

    > Неспортивно.
    Подаю жалобу на перерассмотрение вердикта :)
  • Игорь Шевченко © (27.03.08 00:26) [65]

    > Нет, не так получается, а вот как: я вынуждаю функцию затирать
    > не те кластеры, где располагался файл,
    > а новые, совершенно другие. Что она с успехом и делает :
    > )
    > И считываю я не из "скопированных класеров" а из "старых",
    >  которые в результате
    > остались на диске безхозными и не затертыми. :)


    Ну я говорю, проще скопировать файл перед затиранием. Неспортивно.
    Под "делать все, что хочешь", я, разумеется не имел в виду создание копии незатертых данных.
  • Riply © (27.03.08 01:14) [66]
    >  [65] Игорь Шевченко ©   (27.03.08 00:26)
    Еще раз попробую снять обвинение в неспортивом поведении :)

    > Под "делать все, что хочешь", я, разумеется не имел в виду создание копии незатертых данных.

    О какой копии идет речь ? Пока не начался цикл затирания, я даже файл не открываю.
    Только после этого получаю Pointers даю команду на перемещение.
    К этому времени в цикле уже обработана чать данных.
    Было бы нелогично предполагать, что система будет перемещать старые(уже никому не нужные данные),
    чтобы потом их затирать. Она просто скинет уже обработанные данные в новое место и продолжит запись
    в новые кластеры. (Мой первый пример подтверждает это предположение)
    Так что копии, в данном случае, не создается, а только переопределяется место записи. (Это надеюсь спортивно ? :)
    Здесь, конечно, мне попалась облегченная задача.
    Если бы буфер для затирания был не 1024, а равен кластеру,
    еще лучше "объединению" кластеров (обычно это 16 кластеров), то было бы сложнее, но не безнадежно :)
    Трудности возникли бы и с большими файлами.
    Но мы же искали не способ затирания, а контрпример.
    И с этой задачей, как мне кажется, нам удалось справиться.
    Во всяком случае показано, что при обычной записи в файл,
    не является фактом ведение записи именно в те кластеры где этот файл располагался.
  • Игорь Шевченко © (27.03.08 01:33) [67]
    Riply ©   (27.03.08 01:14) [66]


    > Во всяком случае показано, что при обычной записи в файл,
    >  
    > не является фактом ведение записи именно в те кластеры где
    > этот файл располагался.


    Да, если при этом работает дефрагментатор, то тоже не является фактом.
    Только я, убей бог, не понимаю, что это значит ?
    Если параллельно с записью происходит копирование файла, то тоже не факт, что копия будет идентична оригиналу.

    И что из этого следует ? Что не надо затирать файлы, когда их одновременно копируют ? Что система может произвольно при записи перераспределить кластеры файла ?

    Нет, их перераспределит ТВОЙ ПРОЦЕСС или процесс дефрагментатора, но никак не система сама собой.

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

    Этак каждый гражданин себе веревок настрижет, польт не напасешься.
  • Riply © (27.03.08 02:10) [68]
    > [67] Игорь Шевченко ©   (27.03.08 01:33)
    > Да, если при этом работает дефрагментатор, то тоже не является фактом.
    > Только я, убей бог, не понимаю, что это значит ?

    Это означает то, что ответ "записать в файл нули" на вопрос
    "Как удалить файл со всем, чтобы восстановить было нельзя?"
    является не совсем корректным. Только и всего :)

    > Что система может произвольно при записи перераспределить кластеры файла ?
    > Нет, их перераспределит ТВОЙ ПРОЦЕСС или процесс дефрагментатора, но никак не система сама собой.
    К сожалению, я не знаю как поведет себя система. Ибо неисповедима :)
    Вдруг она решит, что при записи именно в такой то файл, ей удобнее работать так-то и так-то. Черт ее знает :)

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

    В такой постановке, это довольно не просто.
    Этим процессом может оказаться драйвер, какого нибудь супер-пупер виртуального диска.
    Но я буду иметь это ввиду и постоянно следить не имело ли это место.
    Благо работаю то с файловой системой.

    P.S.
    Я могу не знать, ошибаться, не понимать чего-то, но никак не передергивать или подтасовывать факты.

    P.P.S.
    И вообще, у меня очень спортивное поведение.
    Решила объявить это сама, а то вдруг кто не догадается :)
  • Игорь Шевченко © (27.03.08 09:46) [69]
    Riply ©   (27.03.08 02:10) [68]


    > К сожалению, я не знаю как поведет себя система. Ибо неисповедима
    > :)


    Система вполне исповедима бо написана согласно детерминированным алгоритмам.

    Я напомню из поста [14]

    "Я воспроизводила, примерно, такое:
    Создавала файл, например, занимающий восемь кластеров с "номерами":
    0..3,  128...131.
    И после "обычной" записи в него его картинка становилась: 0..7.
    Я не утверждаю, что это происходит всегда,
    но в моих тестах это повторилось несколько раз."

    У меня небольшой вопрос, что значит "обычной" записи в твоих словах ?
    С параллельно работающим дефрагментатором или иной перемещалкой кластеров ?


    > В такой постановке, это довольно не просто.
    > Этим процессом может оказаться драйвер, какого нибудь супер-
    > пупер виртуального диска.
    > Но я буду иметь это ввиду и постоянно следить не имело ли
    > это место.
    > Благо работаю то с файловой системой.


    Обычный диск, на нем обычная система NTFS, параллельно не запущено пермещающих кластеры процессов. Возможна ли ситуация, когда при записи файла (не сжатого, не разреженного) по месту, его распределение кластеров поменяется ?
  • Riply © (27.03.08 10:00) [70]
    > [69] Игорь Шевченко ©   (27.03.08 09:46)
    > У меня небольшой вопрос, что значит "обычной" записи в твоих словах ?
    > С параллельно работающим дефрагментатором или иной перемещалкой кластеров ?

    Игорь, к сожалению, я не могу дать четкого ответа.
    В то время мне и голову не приходило, что кто-то кроме системы может это делать.
    Едиственное, что могу сказать: дефрагментатор точно не был запущен :)
    Насчет других "перемещалок кластеров" не уверена.
    Например, я не знаю как работает "DAEMON Tools". (тогда он у меня стоял).
    Что было еще не помню. "Norton Unerase" может ?

    Соответственно не могу дать однозначного ответа и на это вопрос:
    > Обычный диск, на нем обычная система NTFS, параллельно не запущено пермещающих кластеры процессов.
    > Возможна ли ситуация, когда при записи файла (не сжатого, не разреженного)
    > по месту, его распределение кластеров поменяется ?

    Единственное, что могу утверждать, что "переезд" во время записи возможен.
    А кто тому виной ... ответить не готова.   (Пока :)

    P.S.
    Есть один вариант теста... Надо хорошенько его обдумать.
    Может он и поможет нам докапаться ло истины :)
  • Игорь Шевченко © (27.03.08 10:14) [71]

    > Единственное, что могу утверждать, что "переезд" во время
    > записи возможен.


    Пример в студию
  • Riply © (27.03.08 10:19) [72]
    >  [71] Игорь Шевченко ©   (27.03.08 10:14)
    > Пример в студию

    Тот, который я описывала выше ?
    Мне понадобится время для написания кода, пригодного к компиляции.
  • clickmaker © (27.03.08 10:37) [73]
    а о чем речь вообще?
    что нельзя так затереть файл, чтобы не было возможности восстановить?
  • Riply © (27.03.08 11:01) [74]
    > [70] Riply ©   (27.03.08 10:00)
    > Единственное, что могу утверждать, что "переезд" во время записи возможен.

    Чуть подумав, изменю формулировку:
    "возможен "переезд" во время работы цикла while Condition do WriteFile"
    Ибо именно это происходит в моем примере.
  • Riply © (27.03.08 11:03) [75]
    > [73] clickmaker ©   (27.03.08 10:37)
    > а о чем речь вообще?
    > что нельзя так затереть файл, чтобы не было возможности восстановить?

    Обо всем понемножку. И об этом, в том числе :)
    Точнее не "нельзя", а очень сложно :)
  • clickmaker © (27.03.08 11:18) [76]

    > [75] Riply ©   (27.03.08 11:03)

    ну так, и документ, скормленный шредеру, тоже можно восстановить при желании )
    только кому это интересно, кроме налоговой и ГРУ? )
  • Riply © (27.03.08 11:24) [77]
    > [76] clickmaker ©   (27.03.08 11:18)
    > ну так, и документ, скормленный шредеру, тоже можно восстановить при желании )
    > только кому это интересно, кроме налоговой и ГРУ? )

    Ну... например, возможно, автор этой ветки, полагает, что за его данными может
    охотиться одна из этих благославенных организаций :)
  • Игорь Шевченко © (27.03.08 11:39) [78]
    Riply ©   (27.03.08 10:19) [72]

    Пример в студию, когда при обычной записи и при отсутствие процесса, перемещающего кластеры, распределение кластеров может измениться при перезаписи по месту несжатого и неразреженного файла.
  • Riply © (27.03.08 11:47) [79]
    > [78] Игорь Шевченко ©   (27.03.08 11:39)
    > Пример в студию, когда при обычной записи и при отсутствие процесса, перемещающего кластеры,
    > распределение кластеров может измениться при перезаписи по месту несжатого и неразреженного файла.

    Игорь, так я же в том утверждении написала: "А кто тому виной ... ответить не готова."
    Я имела ввиду, что не знаю кто перемещал "процесс, перемещающий кластеры" или система.
    Sorry, если непонятно выразилась.
  • Игорь Шевченко © (27.03.08 11:51) [80]
    Riply ©   (27.03.08 11:47) [79]


    > Я напомню из поста [14]
    >
    > "Я воспроизводила, примерно, такое:
    > Создавала файл, например, занимающий восемь кластеров с
    > "номерами":
    > 0..3,  128...131.
    > И после "обычной" записи в него его картинка становилась:
    >  0..7.
    > Я не утверждаю, что это происходит всегда,
    > но в моих тестах это повторилось несколько раз."


    Ты забыла указать, у тебя при этом, при "обычной" записи, параллельно кластеры перемещались ? Явно твоим процессом или дефрагментатором.
  • guav © (27.03.08 11:55) [81]
    > [73] clickmaker ©   (27.03.08 10:37)
    > что нельзя так затереть файл, чтобы не было возможности
    > восстановить?


    Я бы так сказал, что, скорее всего, простая перезапись приведёт к тому, что файл не будет восстановим. Но "скорее всего" может быть недостаточно, тогда затереть гарантировано может быть сложно. Нужно учитывать кучу всего.

    Например, если после кода [54] файл сразу удалить, то файл может быть восстановим - запись происходит не сразу, может так получиться, что на момент записи писать будет уже некуда и незачем. Соотвественно того же можно достичь не удаляя файл, а просто чита его через прямой доступ к тому сразу после затирания.
  • Игорь Шевченко © (27.03.08 12:00) [82]
    guav ©   (27.03.08 11:55) [81]


    > Соотвественно того же можно достичь не удаляя файл, а просто
    > чита его через прямой доступ к тому сразу после затирания.
    >


    А можно просто скопировать его перед тем, как затереть :) Возни меньше.
  • guav © (27.03.08 12:07) [83]
    > [82] Игорь Шевченко ©   (27.03.08 12:00)

    Я понимаю что не спортивно. Просто пример, что затереть не так просто :)
    Чтобы устранить указаную в [81] проблему, в затиралках используют FILE_FLAG_NO_BUFFERING.

    Я самопроизвольное перемещение наблюдал только на сжатых файлах.
  • Riply © (27.03.08 12:08) [84]
    > [80] Игорь Шевченко ©   (27.03.08 11:51)
    > Ты забыла указать, у тебя при этом, при "обычной" записи, параллельно кластеры перемещались ?
    > Явно твоим процессом или дефрагментатором.

    Тогда я вела запись процедурой, аналогичной WipeFileBySchevchenko,
    только не циклом, а буфером размером равным размеру файла.
    Дефрагментатор запущен не был.
    Насчет пермещающих кластеры процессов ничего сказать не могу.
    Моих не было, а вот не мои могли быть
    (например, стояли Norton Unerase, DAEMON Tools может еще что. Не помню).
    Это те, на кого может пасть подозрение.
    Тогда я о других процессах и не думала.
    Я полагала, что это может делать только система и никто более,
    соответственно не обращала внимания на то, кто еще работает.
  • clickmaker © (27.03.08 12:11) [85]

    > Чтобы устранить указаную в [81] проблему, в затиралках используют
    > FILE_FLAG_NO_BUFFERING

    что, он даже после CloseHandle может быть не записан?
  • guav © (27.03.08 12:31) [86]
    > [85] clickmaker ©   (27.03.08 12:11)

    да.
  • Игорь Шевченко © (27.03.08 12:59) [87]
    guav ©   (27.03.08 12:31) [86]

    Чудные дела творятся на свете. Файл после CloseHandle не записывается на диск...
  • guav © (27.03.08 13:27) [88]
    > [87] Игорь Шевченко ©   (27.03.08 12:59)

    Ок, будет пример или опровержение.
  • Игорь Шевченко © (27.03.08 14:06) [89]
    Я  к чему - вроде пользуюсь системой тихо, мирно, ожидаю, что будет работать, как написано.

    А написано примерно вот так:

    "Buffers are normally maintained by the operating system, which determines the optimal time to write the data automatically to disk: when a buffer is full, when a stream is closed, or when a program terminates normally without closing the stream" (http://msdn2.microsoft.com/en-us/library/9yky46tz.aspx)

    Обсуждение вопроса, будут ли буферы сброшены на диск после CloseHandle, прводится здесь:

    http://www.tech-archive.net/Archive/VC/microsoft.public.vc.mfc/2007-08/msg00925.html
  • guav © (27.03.08 14:44) [90]
    > [89] Игорь Шевченко ©   (27.03.08 14:06)

    Ок. Как Вы объясните стабильно воспроизводимый вывод старого содержимого файла в этом примере (извините что С, Delphi нету. на FAT не работает, т.к. там из номера кластера смещение не получается простым умножением):

    int _tmain(int argc, _TCHAR* argv[])
    {
     HANDLE file;
     DWORD len, sectorlen;
     DWORD ret;
     BYTE *pBuffer;
     STARTING_VCN_INPUT_BUFFER startVcn;
     RETRIEVAL_POINTERS_BUFFER rp;
     HANDLE volume;

     DWORD clusterSize, sectorSize;
     DWORD freeClusters, totalClusters;

     // Узнаём размеры секотра и кластера.
     GetDiskFreeSpace(
       _T("D:\\"), &clusterSize, §orSize, &freeClusters, &totalClusters);

     // Открываем файл
     file = CreateFile(
       _T("D:\\placeholders.hpp"),
       GENERIC_READ | GENERIC_WRITE,
       FILE_SHARE_READ,
       NULL,
       OPEN_EXISTING,
       0,
       0);

     // Узнаём первый кластер
     startVcn.StartingVcn.QuadPart = 0;
     DeviceIoControl(
       file,
       FSCTL_GET_RETRIEVAL_POINTERS,
       &startVcn,
       sizeof(startVcn),
       &rp,
       sizeof(rp),
       &ret,
       NULL);

     // Узнаём размер
     sectorlen = len = GetFileSize(file, NULL);
     // Округляем sectorlen вверх до размера сектора
     if (sectorlen % sectorSize)
     {
       sectorlen += sectorSize - sectorlen % sectorSize;
     }

     pBuffer = malloc(sectorlen);
     // пишем
     memset(pBuffer, 'A', len);
     WriteFile(file, pBuffer, len, &ret, NULL);

     // закрываем и сразу удаляем (если убрать DeleteFile, может начать выводиться новое содержимое).
     CloseHandle(file);
     DeleteFile(_T("D:\\placeholders.hpp"));

     // Теперь читаем напрямую.
     volume = CreateFile(
       _T("\\\\.\\D:"),
       GENERIC_READ,
       FILE_SHARE_READ | FILE_SHARE_WRITE,
       NULL,
       OPEN_EXISTING,
       0,
       NULL);
     rp.Extents[0].Lcn.QuadPart *= sectorSize * clusterSize;
     SetFilePointerEx(volume, rp.Extents[0].Lcn, NULL, FILE_BEGIN);
     memset(pBuffer, 0, sectorlen);
     ReadFile(volume, pBuffer, sectorlen, &ret, NULL);
     CloseHandle(volume);
     // тут выводятся старые данные.
     puts(pBuffer);
     free(pBuffer);
     return 0;
    }

  • Игорь Шевченко © (27.03.08 15:08) [91]
    А давай после вот этого

    WriteFile(file, pBuffer, len, &ret, NULL);

    добавим

     FlushFileBuffers (file) ?
  • Игорь Шевченко © (27.03.08 15:10) [92]

    > Как Вы объясните стабильно воспроизводимый вывод


    Кстати, об этом Riply писала, когда записывала в файл Hello Dolly, а потом читала по секторам. В начинающих ветка была.
  • guav © (27.03.08 15:21) [93]
    > [91] Игорь Шевченко ©   (27.03.08 15:08)

    Ну так будет выдавать строку 'AAAA...'.
    Но сама по себе CloseFile как в [54] буферы таки не сбрасывает сразу.
  • Игорь Шевченко © (27.03.08 15:24) [94]
    guav ©   (27.03.08 15:21) [93]

    А если DeleteFile не делать ? Конечно надо логику смотреть, я не готов объяснить поведение вот так и сразу.
  • guav © (27.03.08 15:26) [95]
    > [94] Игорь Шевченко ©   (27.03.08 15:24)
    > А если DeleteFile не делать ?

    Результат не стабильный тогда, и старые и новые данные могут читаться.
  • guav © (27.03.08 15:31) [96]
    > [95] guav ©   (27.03.08 15:26)

    Если перенести открытие тома в начало и убрать memset(pBuffer, 0, sectorlen), то будут старые чаще чем новые.
  • Игорь Шевченко © (27.03.08 16:33) [97]
    guav ©   (27.03.08 15:31) [96]

    Значит что-то где-то кешируется. Весьма вероятно, что и старые сектора могут браться из кэша при прямом чтении диска, кстате
  • guav © (27.03.08 16:55) [98]
    > [97] Игорь Шевченко ©   (27.03.08 16:33)

    Есть основания утверждать, что кэшируется именно запись.
    При DeleteFile данные читаются долго после перезаписи.
    FILE_FLAG_NO_BUFFERING или FlushFileBuffers работает.
    Без FILE_FLAG_NO_BUFFERING запись кэшируется.
    CloseFile этот кэш не сбрасывает.
  • guav © (27.03.08 16:58) [99]
    > [97] Игорь Шевченко ©   (27.03.08 16:33)
    > Весьма вероятно, что и старые сектора могут браться из кэша
    > при прямом чтении диска, кстате

    При чтении с диска можно указать FILE_FLAG_NO_BUFFERING, на результат не повлияет.
    Более того, я не просто так делаю
    // Округляем sectorlen вверх до размера сектора
    if (sectorlen % sectorSize)
    {
      sectorlen += sectorSize - sectorlen % sectorSize;
    }
    Даже без FILE_FLAG_NO_BUFFERING том ведёт себя как с FILE_FLAG_NO_BUFFERING, а запись/чтение блока с размером некратным размеру сектора число без буфера не получится.
  • Игорь Шевченко © (27.03.08 17:09) [100]
    guav ©   (27.03.08 16:58) [99]

    И все-таки мне интересно, почему нужен DeleteFile.
  • guav © (27.03.08 18:47) [101]
    > [100] Игорь Шевченко ©   (27.03.08 17:09)

    Без DeleteFile тоже работает.
    Но буфер с буквами A когда-нибудь будет записан.
    А если файл сразу удалить, то буфер с буквами А уже не будет нужен.

    "... Скажем, много лет назад существовала программа для Linux, которая заполняла нули в блоки данных перед их освобождением, однако ОС откладывала запись. Позднее ОС замечала, что блок свободен, и вообще не записывала нули на диск. Кроме того, многие программы предполагают, что при записи данных в существующий файл ОС будет использовать те же блоки данных. Однако ОС также может выделить новые блоки данных, и в этом случае содержимое файла останется на диске."
    Брайан Кэрриэ, "Криминалистический анализ файловых систем", с 175
  • Игорь Шевченко © (27.03.08 20:25) [102]

    > Однако ОС также может выделить новые блоки данных, и в этом
    > случае содержимое файла останется на диске


    Вот этот момент надо бы подкрепить.
  • Riply © (28.03.08 11:20) [103]
    Допустим, система пытается записать на диск и
    у нее не получается (например, кластер файла оказался помечен как плохой), а прочитать может.
    Как она поступает в таком случае ?
  • Игорь Шевченко © (28.03.08 12:51) [104]
    Riply ©   (28.03.08 11:20) [103]


    > Как она поступает в таком случае ?


    в EventLog пишет
 
Конференция "WinAPI" » Как удалить файл без восстановления [D7]
Есть новые Нет новых   [134433   +21][b:0.001][p:0.008]