Случайные сбои MoveFileEx в Vista - PullRequest
       18

Случайные сбои MoveFileEx в Vista

7 голосов
/ 30 сентября 2008

Я заметил, что запись в файл, его закрытие и перемещение в место назначения случайно завершаются неудачно в Vista. В частности, MoveFileEx () вернет ERROR_ACCESS_DENIED без видимой причины. Это происходит по крайней мере в Vista SP1 (32 бит). Не бывает на XP SP3.

Нашел эту ветку в интернете примерно об одной и той же проблеме, без реальных решений. Пока что похоже, что ошибка вызвана поисковым индексатором Vista, см. Ниже.

Приведенного примера кода достаточно, чтобы воспроизвести проблему. Я также вставляю это здесь:

#include <windows.h>
#include <stdlib.h> 
#include <stdio.h> 

bool test() {
    unsigned char buf[] = {
        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 
        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 
    }; 
    HANDLE h; 
    DWORD nbytes; 
    LPCTSTR fn_tmp = "aaa"; 
    LPCTSTR fn = "bbb"; 
    h = CreateFile(fn_tmp, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0); 
    if (h == INVALID_HANDLE_VALUE) return 0; 
    if (!WriteFile(h, buf, sizeof buf, &nbytes, 0)) goto error; 
    if (!FlushFileBuffers(h)) goto error; 
    if (!CloseHandle(h)) goto error; 
    if (!MoveFileEx(fn_tmp, fn, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH)) { 
        printf("error=%d\n", GetLastError()); 
        return 0; 
    } 
    return 1; 
error: 
    CloseHandle(h); 
    return 0; 
} 

int main(int argc, char** argv) { 
    unsigned int i; 
    for (i = 0;; ++i) { 
        printf("*%u\n", i); 
        if (!test()) return 1; 
    } 
    return 0; 
}

Создайте это как консольное приложение с Visual Studio. Правильным поведением будет бесконечный цикл, который печатает номера тестов. В Vista SP1 программа завершается после случайного числа итераций (обычно до 100 итераций).

Этого не происходит в Windows XP SP2. Там не работает антивирус вообще; и никаких других странных фоновых процессов (на компьютере установлена ​​ванильная ОС + Visual Studio).

Редактировать : Копая дальше через Process Monitor (спасибо @sixlettervariables), я не вижу ничего особенно плохого. Каждая итерация теста приводит к 176 операциям на диске, большинство из которых происходит от SearchProtocolHost.exe (поисковый индексатор). Если служба индексирования поиска остановлена, ошибок не возникает, поэтому похоже, что это виновник.

Во время сбоя (когда приложение получает ERROR_ACCESS_DENIED), SearchProtocolHost.exe имеет два файла CreateFile (s) для файла определения (bbb), открытых в режимах совместного использования для чтения / записи / удаления, поэтому все должно быть в порядке. За одним из открытий следует оппортунистическая блокировка (FSCTL_REQUEST_FILTER_OPLOCK), может, в этом причина?

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

Но это не реальное решение . Я имею в виду, что если приложение не может рассчитывать на то, что сможет создать файл и переименовать его, потому что какой-то поисковый индексатор Vista с ним не справляется, это просто безумие ! Должен ли он продолжать попытки? Кричать на пользователя (что очень нежелательно)? Делать что-нибудь еще?

Ответы [ 4 ]

4 голосов
/ 30 сентября 2008

Я предлагаю вам использовать Process Monitor (редактировать: художник, ранее известный как FileMon) , чтобы посмотреть и увидеть, какое именно приложение мешает. Он может показать вам всю трассировку вызовов файловой системы, сделанных на вашем компьютере.

(редактировать: спасибо @moocha за изменения в приложении)

1 голос
/ 30 сентября 2008

Я бы сказал, что это либо ваш антивирус, либо Windows Indexing портят файл в одно и то же время. Можете ли вы запустить тот же тест без антивируса. Затем запустите его снова, убедившись, что временный файл создан где-то, что не проиндексировано Windows Search?

0 голосов
/ 02 октября 2008

В Windows есть специальное место для хранения файлов приложения, и я не думаю, что оно проиндексировано (по крайней мере, по умолчанию). В Vista путь такой:

C: \ Users \ имя пользователя \ AppData

Я предлагаю вам положить туда свои файлы, если это подходит для вашего приложения.

0 голосов
/ 30 сентября 2008

Это обычно означает, что что-то еще имеет открытый дескриптор рассматриваемого файла, возможно, запущен активный антивирусный сканер? Вы пытались запустить что-то вроде Process Monitor с сайта Sysinternals ? Вам следует отфильтровать все файловые операции и получить более полное представление о том, что происходит под капотом.

...