Может DropBox вмешиваться в DeleteFile () / rename () - PullRequest
0 голосов
/ 07 октября 2018

У меня был следующий код, который выполнялся каждые две минуты в течение всего дня:

int sucessfully_deleted = DeleteFile(dest_filename);

if (!sucessfully_deleted)
{
    // this never happens
}

rename(source_filename,dest_filename);

Раз в несколько часов переименование () завершалось с ошибкой errno = 13 (EACCES).Все файлы находились в каталоге DropBox, и я догадывался, что причиной может быть DropBox.Я подумал, что вполне возможно, что функция DeleteFile () может возвращать с ненулевым success_deleted, но на самом деле DropBox все еще может быть занята чем-то, связанным с удалением, которое препятствовало успешному выполнению rename ().Затем я изменил rename () на my_rename (), который будет пытаться переименовать (), а в случае любой ошибки будет Sleep () в течение одной секунды и попытаться во второй раз.Конечно же, это сработало отлично с тех пор.Более того, я получаю диагностическое сообщение, отображающее ошибки при первой попытке каждые несколько часов.Он никогда не подводил со второй попытки.

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

Действительно, я хотел бы, чтобы новая функция super_delete () не возвращалась, пока файл не будет правильно удален и завершен во всех отношениях.

Ответы [ 2 ]

0 голосов
/ 07 октября 2018

при запросе Windows на удаление файла действительно никогда не удаляйте файл просто.он помечает его FCB ( Блок управления файлами ) специальным флагом (FCB_STATE_DELETE_ON_CLOSE).реальное удаление будет только тогда, когда будет закрыт последний дескриптор файла.

Функция DeleteFile помечает файл для удаления при закрытии.Следовательно, удаление файла не происходит до тех пор, пока последний дескриптор файла не будет закрыт.Последующие вызовы CreateFile для открытия файла завершаются неудачно с ERROR_ACCESS_DENIED.

также, если существует раздел (файл с отображением в памяти), открытый для файла - файл даже не может быть помечен для удаления.Ошибка вызова API с STATUS_CANNOT_DELETE.поэтому вообще невозможно всегда удалять файл.

в случае, если существуют другие открытые дескрипторы файла (но не раздел!), начинающиеся с windows 10 rs1, существует новый функционал для удаления - FileDispositionInformationEx с помощью FILE_DISPOSITION_POSIX_SEMANTICS.в этом случае:

Обычно файл, помеченный для удаления, фактически не удаляется до тех пор, пока все открытые дескрипторы для файла не будут закрыты, а количество ссылок для файла равно нулю.При маркировке файла для удаления с использованием FILE_DISPOSITION_POSIX_SEMANTICS ссылка удаляется из видимого пространства имен, как только закрывается дескриптор удаления POSIX, но потоки данных файла остаются доступными для других существующих дескрипторов, пока последний дескриптор не имеетбыл закрыт.

ULONG DeletePosix(PCWSTR lpFileName)
{
    HANDLE hFile = CreateFileW(lpFileName, DELETE, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 
        FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT, 0);

    if (hFile == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    static FILE_DISPOSITION_INFO_EX fdi = { FILE_DISPOSITION_DELETE| FILE_DISPOSITION_POSIX_SEMANTICS };

    ULONG dwError = SetFileInformationByHandle(hFile, FileDispositionInfoEx, &fdi, sizeof(fdi)) 
        ? NOERROR : GetLastError();

    // win10 rs1: file removed from parent folder here
    CloseHandle(hFile);

    return dwError;
}
0 голосов
/ 07 октября 2018

Обновление

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

Теперь я понимаю, что DeleteFile завершается успешно, но переименование происходит сразу после этого.Это может быть просто проблемой синхронизации с файловой системой.После вызова DeleteFile файл будет удален, когда ОС фиксирует изменения в файловой системе.Это может не появиться сразу.Если вам нужно выполнить несколько операций с одним и тем же путем, вы должны взглянуть на транзакции https://docs.microsoft.com/it-it/windows/desktop/api/winbase/nf-winbase-deletefiletransacteda.

- СТАРЫЙ ОТВЕТ -

Это правильно.Если другое приложение обрабатывает этот файл, DeleteFile завершится ошибкой.Ссылаясь на документы MSDN https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-deletefile:

The DeleteFile function fails if an application attempts to delete a file that has other handles open for normal I/O or as a memory-mapped file (FILE_SHARE_DELETE must have been specified when other handles were opened).

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

...