سؤال

Objective : I am trying to send some files from my client to server. I am using "rsync" for transferring the data. I am using CreateProcess APi and passing the rsync path along with the parameters.

Positive Case: When i send data from local drives like "C:" is where my windows is installed the above method works properly and transfers data.

Problem : When i try to send data of a mapped drive (shared network drive) . The CreateProcess completes but the error which i get is rsync cannot find the file. The same rsync command , when i run on a command prompt all files are transferred successfully without any error but fails in transferring files with CreateProcess.

Code :

    int CreateRsyncProcess(const wchar_t * ptrCommand)
    {
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        SECURITY_ATTRIBUTES sap,sat,sao;
        HANDLE out;
        DWORD pwExit;

        //init the STARTUPINFO struct
        memset(&si,0,sizeof(si));
        si.cb=sizeof(si);

        wstring cmd = L"";
        cmd.append(ptrCommand);


        //proc sec attributes
        sap.nLength=sizeof(SECURITY_ATTRIBUTES);
        sap.lpSecurityDescriptor= NULL;
        sap.bInheritHandle=1;

        //thread sec attributes
        sat.nLength=sizeof(SECURITY_ATTRIBUTES);
        sat.lpSecurityDescriptor= NULL;
        sat.bInheritHandle=1;


        //create the proc
        if(!CreateProcess(NULL,(LPWSTR)cmd.c_str(),&sap,&sat,1,CREATE_NO_WINDOW,NULL,NULL,&si,&pi))
        {
            DWORD err = GetLastError();
            if(out != INVALID_HANDLE_VALUE)
                CloseHandle(out);

            return 1;
        }

        //wait till the proc ends

        WaitForSingleObject(pi.hProcess,INFINITE);

        GetExitCodeProcess(pi.hProcess,&pwExit);

        //close all
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        if(out != INVALID_HANDLE_VALUE)
            CloseHandle(out);
        TerminateProcess(pi.hProcess,0);


        return pwExit;

}

Rsync Cmd : "C:\Program Files\cwRsync\bin\rsync.exe" -cvriHPDkREL --no-implied-dirs --stats -e '"C:\Program Files\cwRsync\bin\ssh" -o StrictHostKeyChecking=no -i "C:\Program Files\cwRsync\bin\rsync-key"' "/cygdrive/Z/64Bit" user@server.com:~/6a90c592-2b3b-4088-8942-2106776c863a/

Is it happening because of some security related issue or rights issue wit CreateProcess or some thing else? Please help as i am stuck on this.

Thanks

EDIT: : This is working fine as a normal process but when i run it in a service it fails. So basically the problem now is the service is not accessing the network shares. Any workarounds for that?

هل كانت مفيدة؟

المحلول 2

Since apparently you are running a Service, you probably need to load the enviroment to have access to the mapped folders.

Something like this.

    DWORD dwIdCurrentSession = 0xFFFFFFFF;

    WTS_SESSION_INFO* pSessionInfo = NULL;          
    DWORD dwSessionsCount = 0;
    if(WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwSessionsCount))
    {   
        for(int i=0; i<(int)dwSessionsCount; i++)
        {
            WTS_SESSION_INFO &si = pSessionInfo[i];
            if(si.State == WTSActive)
            {                                                       
                dwIdCurrentSession = si.SessionId;
                break;
            }
        }

        WTSFreeMemory(pSessionInfo);    
    }

    if(dwIdCurrentSession != 0xFFFFFFFF)
    {
        HANDLE hLoggedOnUserToken = NULL;           
        // Get Session User Token   
        if(WTSQueryUserToken(dwIdCurrentSession, &hLoggedOnUserToken))                          
        {                   
            LPVOID lpEnviroment = NULL;
            if(CreateEnvironmentBlock(&lpEnviroment, hLoggedOnUserToken, false))
            {               
                STARTUPINFO si;
                PROCESS_INFORMATION pi;

                ZeroMemory( &si, sizeof(si) );
                si.cb = sizeof(si);
                ZeroMemory( &pi, sizeof(pi) );

                // Create Process
                if(CreateProcessAsUser(hLoggedOnUserToken,
                    NULL,
                    (LPWSTR)cmd.c_str(),
                    NULL,
                    NULL,
                    FALSE,
                    CREATE_UNICODE_ENVIRONMENT,
                    lpEnviroment,
                    NULL,
                    &si,
                    &pi )
                ) 
                {   
                    // Wait for finish......

                    // Clean up
                    CloseHandle( pi.hProcess );
                    CloseHandle( pi.hThread );                                  
                }

                DestroyEnvironmentBlock(lpEnviroment);
            }

            CloseHandle(hLoggedOnUserToken);    
        }
    }

نصائح أخرى

Mapped drives are per session - services in an isolated session can't access mapped drives in user sessions. You'll need to map the drives in the service session, or use UNC paths (instead of mapped drive letters) and give the service users access to the share.

What specific operating system, for example Windows 7 32-bit, Windows 7 64-bit, etc., are you using? Also, do you have UAC enabled? If you do have UAC enabled, does the problem go away when you run the application as an administrator.

Depending on what your answer to these questions are, I may be able to provide further assistance. I would have to do some research though.

At the moment, if UAC is indeed your problem, my only suggestion is that you investigate the possibility of using ShellExecuteEx instead. The RunElevated function found at Riding the Vista UAC elevator, up and down might be of use to you. For the sake of convenience I will include the function here.

BOOL RunElevated(
  HWND hwnd, LPCTSTR pszPath,
  LPCTSTR pszParameters = NULL, LPCTSTR pszDirectory = NULL)
{
  SHELLEXECUTEINFO shex;
  memset( &shex, 0, sizeof( shex) );

  shex.cbSize = sizeof(SHELLEXECUTEINFO);
  shex.fMask = 0;
  shex.hwnd = hwnd;
  shex.lpVerb = _T("runas");
  shex.lpFile = pszPath;
  shex.lpParameters = pszParameters;
  shex.lpDirectory = pszDirectory;
  shex.nShow = SW_NORMAL;
  return ::ShellExecuteEx(&shex);
}

If using ShellExecuteEx is not an option, you can also try the CreateProcessElevated function found at Vista UAC: The Definitive Guide.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top