views:

166

answers:

2

The MSDN says that using ReadDirectoryChangesW implies the calling process having the Backup and Restore privileges.

Does this mean that only process launched under administrator account will work correctly? I've tried the following code, it fails to enable the required privileges when running as a restricted user.

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); } }

Am I doing something wrong? Is there any workaround for using ReadDirectoryChangesW from a non-administrator user account? It seems that the .NET's FileSystemWatcher can do this. Thanks!

UPD: Here is the full code of the class:

  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];   
  };

 }

UPD2: Good news! It turned out the problem really was in the FILE_SHARE_WRITE flag in the call to CreateFile. The notifications did not come unless I was an admin. When I removed this flag, everything is now working ona non-admin account too.

+1  A: 

I have used ReadDirectoryChangesW without requiring administrator rights, at least on Vista. I don't think you need to manually elevate the process in order to use it on a folder the user already has permissions to see.

It would be more helpful to see the actual code you are using to call ReadDirectoryChangesW, including how you create the handle you pass in.

MSN
Thanks! You got it right: creating the handle contained an error - the unneeded FILE_SHARE_WRITE flag
Alex Jenter
+1  A: 

I don't see where MSDN says you need either backup or restore privileges. It instructs you to call CreateFile with the File_Flag_Backup_Semantics flag set, and in that flag's description, MSDN says this:

The system ensures that the calling process overrides file security checks when the process has SE_BACKUP_NAME and SE_RESTORE_NAME privileges.

The way I read it, if you have those privileges, then the system will override the file security checks for you. So if you don't have those privileges, then the program will simply continue to be bound by whatever file security checks would ordinarily be in effect.

Rob Kennedy
You are right, I misunderstood what MSDN really says. The problem was in the FILE_SHARE_WRITE flag in the call to CreateFile.
Alex Jenter