CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 11.05.20 18:10
Оценка:
Привет!

Если при создании файла существует папка с таким именем, то CreateFile возвращает AccessDenied, а хотелось бы получать нормальный статус ошибки, например ERROR_ALREADY_EXISTS. Т.е. если я получаю AccessDenied, то чтобы проверить, существует ли объект с таким именем нужно вызвать например FindFirstFile, но в момент его вызова папку могут удалить, и тогда будет непонятно, почему был запрещён доступ. Есть ли какой-нибудь способ решить эту проблему?

Файл должен создаваться как CREATE_NEW, т.к. нужно именно создание нового файла. Хотя при CREATE_ALWAYS аналогично возвращается AccessDenied

Пример кода:

    BOOL b = CreateDirectory(L"D:\\tmp\\d", NULL);
    HANDLE h = CreateFile(L"D:\\tmp\\d", GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD err = GetLastError();
    // err  == ERROR_ACCESS_DENIED
    // если сейчас вызвать FindFirstFile(L"D:\\tmp\\d), то папка уже может быть удалена, и непонятно почему не создался файл
Re: CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 11.05.20 18:24
Оценка:
Нашёл такой способ: создаём файл с рандомным именем, потом пытаемся переименовать, и если существует папка, то ошибка будет как раз ERROR_ALREADY_EXISTS. Вроде подходит для моей задачи


    BOOL b = CreateDirectoryW(L"D:\\tmp\\1\\d", NULL);
    HANDLE h = CreateFile(L"D:\\tmp\\1\\random_name", GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
    CloseHandle(h);


    BOOL res = MoveFileW(L"D:\\tmp\\1\\random_name", L"D:\\tmp\\1\\d");
    DWORD err = GetLastError();
    // err == ERROR_ALREADY_EXISTS - значит существует файл или папка
Re[2]: CreateFile - AccessDenied когда существует папка
От: Сергей Мухин Россия  
Дата: 11.05.20 19:32
Оценка: 1 (1)
Здравствуйте, MuPoB, Вы писали:

MPB>Нашёл такой способ: создаём файл с рандомным именем, потом пытаемся переименовать, и если существует папка, то ошибка будет как раз ERROR_ALREADY_EXISTS. Вроде подходит для моей задачи



MPB>
MPB>    BOOL b = CreateDirectoryW(L"D:\\tmp\\1\\d", NULL);
MPB>    HANDLE h = CreateFile(L"D:\\tmp\\1\\random_name", GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
MPB>    CloseHandle(h);


MPB>    BOOL res = MoveFileW(L"D:\\tmp\\1\\random_name", L"D:\\tmp\\1\\d");
MPB>    DWORD err = GetLastError();
MPB>    // err == ERROR_ALREADY_EXISTS - значит существует файл или папка
MPB>


может проще GetFilAttrbutes c проверкой на INVALID_FILE_ATTRIBUTES и FILE_ATTRIBUTE_DIRECTORY
---
С уважением,
Сергей Мухин
Re[3]: CreateFile - AccessDenied когда существует папка
От: Сергей Мухин Россия  
Дата: 11.05.20 19:37
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:



MPB>> BOOL res = MoveFileW(L"D:\\tmp\\1\\random_name", L"D:\\tmp\\1\\d");

MPB>> DWORD err = GetLastError();
MPB>> // err == ERROR_ALREADY_EXISTS — значит существует файл или папка
MPB>>[/ccode]

СМ>может проще GetFilAttrbutes c проверкой на INVALID_FILE_ATTRIBUTES и FILE_ATTRIBUTE_DIRECTORY

но правильно после получения ошибки, начать анализировать что произошло. нет доступа к файлу (в том числе это директория) и тп
---
С уважением,
Сергей Мухин
Re[4]: CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 11.05.20 19:58
Оценка: 1 (1)
СМ>>может проще GetFilAttrbutes c проверкой на INVALID_FILE_ATTRIBUTES и FILE_ATTRIBUTE_DIRECTORY
СМ>но правильно после получения ошибки, начать анализировать что произошло. нет доступа к файлу (в том числе это директория) и тп

Проблема в том, что между вызовом функции CreateFile и вызовом любой функции, анализирующей ошибку (GetFilAttrbutes, FindFirstFile и т.п.) может произойти всё что угодно, и то, что вернёт функция анализа, будет уже неадекватно. Или если сначала проверить, существует такая папка или нет, а потом создать файл — опять перед созданием состояние ФС может поменяться

Нужно чтобы сразу ошибка была говорящей, а не просто AccessDenied. Создание рандомного файла и его переименование сразу позволяет понять, что директория с таким именем уже существует
Re[5]: CreateFile - AccessDenied когда существует папка
От: Alexander G Украина  
Дата: 12.05.20 16:13
Оценка: 5 (2) +1
Здравствуйте, MuPoB, Вы писали:

MPB>Проблема в том, что между вызовом функции CreateFile и вызовом любой функции, анализирующей ошибку (GetFilAttrbutes, FindFirstFile и т.п.) может произойти всё что угодно, и то, что вернёт функция анализа, будет уже неадекватно. Или если сначала проверить, существует такая папка или нет, а потом создать файл — опять перед созданием состояние ФС может поменяться


MPB>Нужно чтобы сразу ошибка была говорящей, а не просто AccessDenied. Создание рандомного файла и его переименование сразу позволяет понять, что директория с таким именем уже существует


Есть решение. После неуспешного CreateFile получить последний NTSTATUS из TEB.

HANDLE h = ::CreateFile(path, 0, 7, 0, OPEN_ALWAYS, 0, 0);
if (h == INVALID_HANDLE_VALUE)
{
   NTSTATUS status = GetLastNtStatus();
   if (status == STATUS_FILE_IS_A_DIRECTORY) { ... }
}


Разве что заминка будет с GetLastNtStatus. Документриованный путь мне неизвестен.
Недокументировано как-то так:
inline NTSTATUS GetLastNtStatus()
{
#if defined(_M_X64)
    return __readgsdword(0x1250);
#elif defined (_M_IX86)
    return __readfsdword(0xBF4);
#else
#error Implement this for ARM or whatever architecture you have
#endif 
}

Магические константы подсмотрел в Википедии.

Более чистым, возможно, будет прямой вызов NtCreateFile / NtOpenFile.
Это более легально с точки зрения документрованности, но потребует большего изменения вызывающего кода.
Русский военный корабль идёт ко дну!
Отредактировано 12.05.2020 16:18 Alexander G . Предыдущая версия .
Re[6]: CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 12.05.20 18:36
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Есть решение. После неуспешного CreateFile получить последний NTSTATUS из TEB.

...
AG>Более чистым, возможно, будет прямой вызов NtCreateFile / NtOpenFile.
AG>Это более легально с точки зрения документрованности, но потребует большего изменения вызывающего кода.

Да, TEB не очень хочется парсить, тут действительно проще NtCreateFile вызвать и статус проверить. Спасибо!
Ну подумаю еще, как лучше сделать, NtCreateFile тоже разной подготовительной работы требует
Re[5]: CreateFile - AccessDenied когда существует папка
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 13.07.20 18:43
Оценка:
Здравствуйте, MuPoB, Вы писали:

MPB>Проблема в том, что между вызовом функции CreateFile и вызовом любой функции, анализирующей ошибку (GetFilAttrbutes, FindFirstFile и т.п.) может произойти всё что угодно, и то, что вернёт функция анализа, будет уже неадекватно. Или если сначала проверить, существует такая папка или нет, а потом создать файл — опять перед созданием состояние ФС может поменяться


Если не секрет, для чего Вы с большой скоростью создаете файлы в каталоге, где кто-то другой со сравнимой скоростью создает свои подкаталоги?
Re[6]: CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 13.07.20 20:34
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Если не секрет, для чего Вы с большой скоростью создаете файлы в каталоге, где кто-то другой со сравнимой скоростью создает свои подкаталоги?


Вообще для файлового менеджера, а ситуация эта гипотетическая, просто не хочется вызывать дополнительную функцию для анализа причины ошибки, тем более что эта дополнительная функция может вернуть ложь
Re[7]: CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 13.07.20 20:40
Оценка:
Вот например ещё такой случай может быть — диск закрыт на запись, там есть папка 123. Пытаемся создать файл 123 — AccessDenied. Если посмотреть, что там существует папка 123, и сказать, что не получилось создать файл из-за конфликта имени с папкой — это неверно. Хотя что вернёт в этом случае NtCreateFile — надо посмотреть
Re[7]: CreateFile - AccessDenied когда существует папка
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 13.07.20 20:49
Оценка:
Здравствуйте, MuPoB, Вы писали:

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


Для файлового менеджера, управляемого вручную, подобная эквилибристика совершенно избыточна. Достаточно вывести системное сообщение об ошибке, снабдив его рекомендацией проверить то-то и то-то.
Re[8]: CreateFile - AccessDenied когда существует папка
От: Sharowarsheg  
Дата: 13.07.20 21:50
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, MuPoB, Вы писали:


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


ЕМ>Для файлового менеджера, управляемого вручную, подобная эквилибристика совершенно избыточна.


Это пока не понадобится скопировать что-то, где сто тыщ директорий и гориллион файлов.
Re[9]: CreateFile - AccessDenied когда существует папка
От: reversecode google
Дата: 13.07.20 21:55
Оценка: +1
S>Это пока не понадобится скопировать что-то, где сто тыщ директорий и гориллион файлов.

это делается через SHFileOperation

а игры с крейт дир, делейт дир, крейт файл и записать что то насильно
да еще и как можно быстрее а то кто то другой может это перезаписать обратно
это точно зловреды
Re[10]: CreateFile - AccessDenied когда существует папка
От: Sharowarsheg  
Дата: 13.07.20 22:00
Оценка:
Здравствуйте, reversecode, Вы писали:


S>>Это пока не понадобится скопировать что-то, где сто тыщ директорий и гориллион файлов.


R>это делается через SHFileOperation


Мне помнится, SHFileOperation было не совсем хорошо, по крайней мере давно когда-то.

R>а игры с крейт дир, делейт дир, крейт файл и записать что то насильно

R>да еще и как можно быстрее а то кто то другой может это перезаписать обратно
R>это точно зловреды

В файл-менеджере, если логи например какие-то копировать куда-то, там не как можно быстрее, но регулярно бывает, что могут из-под ног выдернуть что-то. Ну то есть начинаешь копировать, прочитал список файлов, а когда собрался копировать, файлов уже нет, потому что их в архив свернули.
Re[11]: CreateFile - AccessDenied когда существует папка
От: reversecode google
Дата: 13.07.20 22:07
Оценка:
Здравствуйте, Sharowarsheg, Вы писали:

S>Здравствуйте, reversecode, Вы писали:



S>>>Это пока не понадобится скопировать что-то, где сто тыщ директорий и гориллион файлов.


R>>это делается через SHFileOperation


S>Мне помнится, SHFileOperation было не совсем хорошо, по крайней мере давно когда-то.


именно это да еще и с расширенным кодом ошибок


R>>а игры с крейт дир, делейт дир, крейт файл и записать что то насильно

R>>да еще и как можно быстрее а то кто то другой может это перезаписать обратно
R>>это точно зловреды

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


у тс другая ситуация
начинаем что то писать, ага какое писать с WriteFile ? бред
ну так начинаем писать имя файла которое может вдруг совпадать с именем диры которая там может быть
бац
надо наплевать и насильно переписать эту диру именно в имя такого файла

да за такой функционал в файловом менеджере сразу в зловреды и заносить во все ав базы
Re[11]: CreateFile - AccessDenied когда существует папка
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 14.07.20 06:30
Оценка:
Здравствуйте, Sharowarsheg, Вы писали:

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


Нет никакой разницы, в менеджере или еще где-то. Когда копируешь не свое — всегда существует вероятность, что выдернут посреди процесса. Но это не имеет отношения к обсуждаемой проблеме.
Re[12]: CreateFile - AccessDenied когда существует папка
От: Sharowarsheg  
Дата: 14.07.20 08:04
Оценка: 1 (1)
Здравствуйте, reversecode, Вы писали:

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


R>у тс другая ситуация

R>начинаем что то писать, ага какое писать с WriteFile ? бред

Начинаем с CreateFile() (а как ещё?)

R>ну так начинаем писать имя файла которое может вдруг совпадать с именем диры которая там может быть


Например, если с линуксовой шары тащить исходник FreeBSD, кажется, или чего-то ещё такого рода, я уж забыл за давностью, там есть интересная проблема с тем, что есть одновременно директория и файл, с именами типа Config и config. И такого там заметно больше одного раза.

R>бац

R>надо наплевать и насильно переписать эту диру именно в имя такого файла

Он не спрашивал как переписать, он спрашивал, как понять, почему файл не создался.
Re[12]: CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 14.07.20 08:09
Оценка:
Здравствуйте, reversecode, Вы писали:


R>у тс другая ситуация

R>начинаем что то писать, ага какое писать с WriteFile ? бред
R>ну так начинаем писать имя файла которое может вдруг совпадать с именем диры которая там может быть
R>бац
R>надо наплевать и насильно переписать эту диру именно в имя такого файла

R>да за такой функционал в файловом менеджере сразу в зловреды и заносить во все ав базы


У тебя профдеформация на почве зловредов? Какой функционал ты увидел?
Для альтернативно одарённых — нужно копировать файл из одной папки в другую. Но в ней может быть подпапка с таким же именем. И что пользователю показать? AccessDenied, как в TotalCommander?
Как ты собрался копировать файл без использования WriteFile?
Re[13]: CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 14.07.20 08:13
Оценка:
Здравствуйте, Sharowarsheg, Вы писали:

S>Здравствуйте, reversecode, Вы писали:


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


R>>у тс другая ситуация

R>>начинаем что то писать, ага какое писать с WriteFile ? бред

S>Начинаем с CreateFile() (а как ещё?)


R>>ну так начинаем писать имя файла которое может вдруг совпадать с именем диры которая там может быть


S>Например, если с линуксовой шары тащить исходник FreeBSD, кажется, или чего-то ещё такого рода, я уж забыл за давностью, там есть интересная проблема с тем, что есть одновременно директория и файл, с именами типа Config и config. И такого там заметно больше одного раза.


R>>бац

R>>надо наплевать и насильно переписать эту диру именно в имя такого файла

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



Да, нужно именно понять причину, директорию зачем переписывать, странные мысли в голове у reversecode
Re[10]: CreateFile - AccessDenied когда существует папка
От: MuPoB  
Дата: 14.07.20 08:25
Оценка:
Здравствуйте, reversecode, Вы писали:


S>>Это пока не понадобится скопировать что-то, где сто тыщ директорий и гориллион файлов.


R>это делается через SHFileOperation


R>а игры с крейт дир, делейт дир, крейт файл и записать что то насильно

R>да еще и как можно быстрее а то кто то другой может это перезаписать обратно
R>это точно зловреды

А SHFileOperation по твоему сама копирует файлы? Без использования CreateFile+WriteFile? И ты думаешь что нормальная ошибка там вернётся?

Если ты не в курсе, то NtCreateFile официально документирована, включена в заголовочные файлы, и может быть использована в прикладном коде без получения её адреса через GetProcAddress

Директорию типа нельзя через CreateDir создавать? А что ещё нельзя?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.