Делаю программу работающую по принципу описанному в статье ms-rem'a "3 способа работы с занятыми файлам", используется 3ий способ. Там (в статье) описано лишь чтение с диска по определенным адресам, а мне хотелось бы сделать запись. Делаю так: получаю номера кластеров, которые занимает некоторый файл (FSCTL_GET_RETRIEVAL_POINTERS). открываю том на чтение/запись: Код (Text): hVolume = CreateFile(Name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS , 0); ... // Смещение файла, относительно начала тома Offset.QuadPart = Clusters[r] * ClusterSize; Offset.QuadPart += SectorStart; // Читаю что было ДО SetFilePointerEx(hVolume, Offset, NULL, FILE_BEGIN); Bytes=0; ReadFile(hVolume, lpBackupData, ClusterSize, &Bytes, NULL); // Записываю свои данные в файл SetFilePointerEx(hVolume, Offset, NULL, FILE_BEGIN); Bytes=0; WriteFile(hVolume, lpData, ClusterSize, &Bytes, NULL); Так вот самые интересности начинаются после того как якобы прошла запись в файл. Повторный вызов ReadFile по тем адресам, где уже прошла запись это подтверждает. НО! на самом деле записи как будто никакой и не происходит. Файл, находящийся на диске - НЕ изменяется. Доступ к файлу через обычное открытие CreateFile("...\file.ext"...) / ReadFile - выдает что файл каким был, таким и остался. В то же время доступ к файлу через полученную карту кластеров выдает что файл изменен. Почему такое происходит? P.S. Работаю в NTFS, в FAT32 - и чтение и запись проходят нормально (естественно я учитываю смещения с учетом таблиц FAT в этом случае.) P.P.S. переменная Name == "\\\\.\\E:" например
а как быть с тем что я открываю том с флагом FILE_FLAG_WRITE_THROUGH? Если это более низкоуровневое кэширование, то как можно заставить систему записывать изменения на диск?
не помогает... ни FlushFileBuffers, ни установка указанных флагов. вообще я нашел только один способ сбрасывать кэш на диск это : DeviceIoControl(hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &Bytes, NULL); DeviceIoControl(hVolume, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &Bytes, NULL); "The system flushes all cached data to the volume before locking it. For example, any data held in a lazy-write cache is written to the volume." Но, естественно, это очень даже не всегда подходит, потому что занятый том просто никто не даст залочить. Также выяснил что кэш сбрасывается на диск, например, при выходе из системы... а вот как его сбросить вручную.. ?
ну из юзермоде использовать CcPurgeCacheSection не получится пожалуй =) а тема на том и закрылась... думаю из под пользовательского режима я уже делаю все что нужно: hVolume = CreateFile(Name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, 0); Эквивалент: ZwCreateFile(&hVolume, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE, &obj, &block, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NO_INTERMEDIATE_BUFFERING | FILE_WRITE_THROUGH, NULL, 0); ... От топикстартера (Zufyxe) : похоже на ринг3 такую вещь не сделать...
возможно, где-то сорец на Delphi видел чтения/записи в собственный запущенный файл, как раз через такой метод.
хмм, как бы найти этот исходник =) а там точно для записи использовался WriteFile? или всё те же средстства для дефрагментации и перемещения кластеров?
не. Там это было в смецилаьном подфоруме - исходники/кладовка/etc. Где выкладывались свои полезные сорцы. Наткнулся совершенно случайно.