Способ WinAPI определить, является ли файл доступным / закрытым

#c #winapi

#c #winapi

Вопрос:

В win32 c ; есть ли способ определить, доступна ли папка / файл? Вы знаете, как, если вы попытаетесь получить доступ к определенной папке в C:/Windows каталог и вы получите всплывающее окно с надписью «Эта папка недоступна».

Может быть, существует константа атрибута файла, которая означает, что файл является приватным? Может быть, что-то вроде FILE_ATTRIBUTE_PRIVATE?

 WIN32_FIND_DATA dirData;

while (FindNextFile( dir, amp;dirData ) != 0 )
{
    // I made the following constant up
    if ( !(fileData.dwFileAttributes amp; FILE_ATTRIBUTE_PRIVATE) )
    {
        // file is accessible so store filepath
        files.push_back( fileData.cFileName );
    }
    else // file is not accessible so dont store
}
  

Или это единственный способ узнать, перейдя:

 dir = FindFirstFileEx( (LPCTSTR)directory.c_str(), FindExInfoStandard, amp;dirData, FindExSearchNameMatch, NULL, 0 );

if ( dir == ??? ) { the file is inaccessible } [/code]
  

Ответ №1:

Лучшее, что можно сделать, это просто попытаться получить к нему доступ.

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

Комментарии:

1. «Доступ запрещен» означает GetLastError()==5 .

Ответ №2:

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

Списки управления доступом в Windows можно использовать практически со всем, на что ссылается дескриптор (файлы, каталоги, процессы, мьютексы, именованные каналы …). Вы можете просмотреть списки управления доступом к файлам, перейдя в свойства файла и просмотрев вкладку «Безопасность».

Итак, в вашем приложении вы на самом деле не хотите проверять наличие флага, а сравнивать ACL файла с учетной записью пользователя, под которой запущено ваше приложение. Проверьте функцию проверки доступа Win32. Я думаю, это именно то, что вы ищете.

Лично я никогда не использовал эту функцию, но если вы ищете решение для Win32 и хотите вызвать функцию, это, вероятно, ваш лучший выбор. Однако, как указывали другие, это может быть слишком сложно. Я всегда использовал _access (или _waccess), который является частью CRT, очень прост в использовании, и вы не теряете производительность, получая дескриптор файла только для его закрытия (в зависимости от того, насколько плотен ваш цикл, эти вызовы могут фактически складываться).

Комментарии:

1. Да, AccessCheck будет работать, но это сложно и сложно использовать. Если вы хотите узнать, можете ли вы открыть файл, самый простой способ — просто попытаться открыть файл и посмотреть, удалось ли вам это.

2. да, я бы тоже никогда его не использовал, но OP искал вызов win32 🙂 Обновил сообщение другой альтернативой

3. Получение дескриптора файла только для его закрытия? Нет, вы должны ИСПОЛЬЗОВАТЬ дескриптор файла для чего-то полезного. Если вы не собираетесь использовать ресурс, почему его разрешения имеют значение?

4. @Ben — Я могу придумать множество сценариев. Например, проверка сервера при запуске, чтобы убедиться, что каталог для приема клиентских файлов доступен. Или утилита настройки, проверяющая, что файл доступен для записи, потому что это понадобится позже совершенно другому процессу, но та же утилита не намерена фактически читать файл во время проверки.

5. Как насчет того, что вы хотите получить доступ к папке? Как открыть папку для доступа на запись.

Ответ №3:

 int _access( 
   const char *path, 
   int mode 
);
  

Простой в использовании:

http://msdn.microsoft.com/en-us/library/1w06ktdy(v=vs.80).aspx

Комментарии:

1. Для меня в Win7 это не привело к появлению сообщения «Эта папка недоступна».

Ответ №4:

Да, Аарон Баллман, ты босс! О боже, о боже! Что я мог бы использовать некоторые полезные ругательства, чтобы выразить свою радость прямо сейчас.

https://blog.aaronballman.com/2011/08/how-to-check-access-rights / — это ссылка на пример проверки прав доступа в win32 по пути fpath. И объяснение плохо документированной функции проверки доступа win32. Ниже приведен код.

 bool canAccessPath( LPCTSTR folderName, DWORD genericAccessRights )
{
    bool bRet = 0;
    DWORD length = 0;

    if (!::GetFileSecurity( folderName, OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, NULL, 0, amp;length ) amp;amp;
            ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
    {
        PSECURITY_DESCRIPTOR security = static_cast< PSECURITY_DESCRIPTOR >( ::malloc( length ) );

        if (security amp;amp; ::GetFileSecurity( folderName, OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, security, length, amp;length ))
        {
            HANDLE hToken = NULL;

            if (::OpenProcessToken( ::GetCurrentProcess(), TOKEN_IMPERSONATE|TOKEN_QUERY|TOKEN_DUPLICATE|STANDARD_RIGHTS_READ, amp;hToken ))
            {
                HANDLE hImpersonatedToken = NULL;

                if (::DuplicateToken( hToken, SecurityImpersonation, amp;hImpersonatedToken ))
                {
                    GENERIC_MAPPING mapping = { 0xFFFFFFFF };
                    PRIVILEGE_SET privileges = { 0 };
                    DWORD grantedAccess = 0, privilegesLength = sizeof( privileges );
                    BOOL result = FALSE;

                    mapping.GenericRead = FILE_GENERIC_READ;
                    mapping.GenericWrite = FILE_GENERIC_WRITE;
                    mapping.GenericExecute = FILE_GENERIC_EXECUTE;
                    mapping.GenericAll = FILE_ALL_ACCESS;

                    ::MapGenericMask( amp;genericAccessRights, amp;mapping );

                    if (::AccessCheck( security, hImpersonatedToken, genericAccessRights,
                            amp;mapping, amp;privileges, amp;privilegesLength, amp;grantedAccess, amp;result ))
                    {
                     bRet = result == TRUE;
                    }

                    ::CloseHandle( hImpersonatedToken );
                }

                ::CloseHandle( hToken );
            }

            ::free( security );
        }
    }

    return bRet;
}
  

Не стесняйтесь зайти на его веб-сайт и проверить его работу. Я уверен, что у него есть более интересные вещи.