В MSDN говорится, что использование ReadDirectoryChangesW подразумевает обработку вызовов, имеющую полномочия Резервного копирования и Восстановления.
Это означает, что только процесс, запущенный в соответствии с учетной записью администратора, будет работать правильно?
Я попробовал следующий код, ему не удается включить требуемые полномочия при выполнении как ограниченный пользователь.
void enablePrivileges()
{
enablePrivilege(SE_BACKUP_NAME);
enablePrivilege(SE_RESTORE_NAME);
}
void enablePrivilege(LPCTSTR name)
{
HANDLE hToken;
DWORD status;
if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_PRIVILEGES tp = { 1 };
if( ::LookupPrivilegeValue(NULL, name, &tp.Privileges[0].Luid) )
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
BOOL result = ::AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
verify (result != FALSE);
status = ::GetLastError();
}
::CloseHandle(hToken);
}
}
Я делаю что-то не так? Есть ли какое-либо обходное решение для использования ReadDirectoryChangesW от учетной записи пользователя неадминистратора? Кажется, что FileSystemWatcher.NET может сделать это.Спасибо!
Обновление: Вот полный код класса:
class DirectoryChangesWatcher
{
public:
DirectoryChangesWatcher(wstring directory)
{
enablePrivileges();
hDir = ::CreateFile(directory.c_str(),
FILE_LIST_DIRECTORY | FILE_FLAG_OVERLAPPED,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
ensure (hDir != INVALID_HANDLE_VALUE, err::SystemException);
::ZeroMemory(&overlapped, sizeof(OVERLAPPED));
overlapped.hEvent = dirChangedEvent.getHandle();
}
~DirectoryChangesWatcher() { ::CloseHandle(hDir); }
public:
Event& getEvent() { return dirChangedEvent; }
FILE_NOTIFY_INFORMATION* getBuffer() { return buffer; }
public:
void startAsyncWatch()
{
DWORD bytesReturned;
const BOOL res = ::ReadDirectoryChangesW(
hDir,
&buffer,
sizeof(buffer),
TRUE,
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE,
&bytesReturned,
&overlapped,
NULL);
ensure(res != FALSE, err::SystemException);
}
private:
void enablePrivileges()
{
enablePrivilege(SE_BACKUP_NAME);
enablePrivilege(SE_RESTORE_NAME);
}
void enablePrivilege(LPCTSTR name)
{
HANDLE hToken;
DWORD status;
if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_PRIVILEGES tp = { 1 };
if( ::LookupPrivilegeValue(NULL, name, &tp.Privileges[0].Luid) )
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
BOOL result = ::AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
verify (result != FALSE);
status = ::GetLastError();
}
::CloseHandle(hToken);
}
}
private:
HANDLE hDir;
OVERLAPPED overlapped;
Event dirChangedEvent;
FILE_NOTIFY_INFORMATION buffer[1024];
};
}
Обновление: Хорошие новости! Оказалось, что проблема действительно была во флаге FILE_SHARE_WRITE в вызове к CreateFile. Уведомления не появлялись, если я не был администратором. Когда я удалил этот флаг, все теперь работает ona неадминистраторская учетная запись также.
Я использовал ReadDirectoryChangesW
, не требуя прав администратора, по крайней мере, в Vista. Я не думаю, что вам нужно вручную повышать уровень процесса, чтобы использовать его в папке, на просмотр которой у пользователя уже есть разрешения.
Было бы более полезно увидеть фактический код, который вы используете для вызова ReadDirectoryChangesW
, включая то, как вы создаете дескриптор, который вы передаете.
Я не вижу, где MSDN говорит, что вам нужны права резервного копирования или восстановления. Он инструктирует вас вызвать CreateFile
с установленным флагом File_Flag_Backup_Semantics
, и в описании этого флага MSDN говорит следующее :
Система гарантирует, что вызывающий процесс отменяет проверки безопасности файлов, когда процесс имеет привилегии
SE_BACKUP_NAME
иSE_RESTORE_NAME
.
Как я читал, если у вас есть эти привилегии, то система отменит проверки безопасности файлов за вас. Так что, если у вас нет этих привилегий, то программа просто продолжит связываться с любыми обычными проверками безопасности файлов.