TEST(CPath, GetPath_FullName) { { ASSERT_EQUALS(CPath().GetPath(), CPath()); ASSERT_EQUALS(CPath().GetFullName(), CPath()); } { const CPath path = Norm(wxT("/home/mule/")); ASSERT_EQUALS(path.GetPath(), Norm(wxT("/home/mule"))); ASSERT_EQUALS(path.GetFullName(), CPath()); } { const CPath path = Norm(wxT("/home/mule")); ASSERT_EQUALS(path.GetPath(), Norm(wxT("/home"))); ASSERT_EQUALS(path.GetFullName(), Norm(wxT("mule"))); } { const CPath path = Norm(wxT("mule")); ASSERT_EQUALS(path.GetPath(), CPath()); ASSERT_EQUALS(path.GetFullName(), Norm(wxT("mule"))); } { const CPath path = Norm(wxT("mule.ext")); ASSERT_EQUALS(path.GetPath(), CPath()); ASSERT_EQUALS(path.GetFullName(), Norm(wxT("mule.ext"))); } }
TEST(CPath, DefaultConstructor) { CPath tmp; ASSERT_FALSE(tmp.IsOk()); ASSERT_EQUALS(tmp, CPath()); ASSERT_FALSE(tmp.FileExists()); ASSERT_FALSE(tmp.DirExists()); ASSERT_EQUALS(wxEmptyString, tmp.GetRaw()); ASSERT_EQUALS(wxEmptyString, tmp.GetPrintable()); ASSERT_EQUALS(CPath(), tmp.GetPath()); ASSERT_EQUALS(CPath(), tmp.GetFullName()); }
ConvStatus CPartFileConvert::performConvertToeMule(const CPath& fileName) { wxString filepartindex; CPath folder = fileName.GetPath(); CPath partfile = fileName.GetFullName(); CPath newfilename; CDirIterator finder(folder); Notify_ConvertUpdateProgressFull(0, _("Reading temp folder"), s_pfconverting->folder.GetPrintable()); filepartindex = partfile.RemoveAllExt().GetRaw(); Notify_ConvertUpdateProgress(4, _("Retrieving basic information from download info file")); CPartFile* file = new CPartFile(); s_pfconverting->partmettype = file->LoadPartFile(folder, partfile, false, true); switch (s_pfconverting->partmettype) { case PMT_UNKNOWN: case PMT_BADFORMAT: delete file; return CONV_BADFORMAT; } CPath oldfile = folder.JoinPaths(partfile.RemoveExt()); { wxMutexLocker lock(s_mutex); s_pfconverting->size = file->GetFileSize(); s_pfconverting->filename = file->GetFileName(); s_pfconverting->filehash = file->GetFileHash().Encode(); } Notify_ConvertUpdateJobInfo(s_pfconverting); if (theApp->downloadqueue->GetFileByID(file->GetFileHash())) { delete file; return CONV_ALREADYEXISTS; } if (s_pfconverting->partmettype == PMT_SPLITTED) { unsigned fileindex; char *ba = new char [PARTSIZE]; try { CFile inputfile; // just count unsigned maxindex = 0; unsigned partfilecount = 0; CPath filePath = finder.GetFirstFile(CDirIterator::File, filepartindex + wxT(".*.part")); while (filePath.IsOk()) { long l; ++partfilecount; filePath.GetFullName().RemoveExt().GetExt().ToLong(&l); fileindex = (unsigned)l; filePath = finder.GetNextFile(); if (fileindex > maxindex) maxindex = fileindex; } float stepperpart; { wxMutexLocker lock(s_mutex); if (partfilecount > 0) { stepperpart = (80.0f / partfilecount); if (maxindex * PARTSIZE <= s_pfconverting->size) { s_pfconverting->spaceneeded = maxindex * PARTSIZE; } else { s_pfconverting->spaceneeded = s_pfconverting->size; } } else { stepperpart = 80.0f; s_pfconverting->spaceneeded = 0; } } Notify_ConvertUpdateJobInfo(s_pfconverting); sint64 freespace = CPath::GetFreeSpaceAt(thePrefs::GetTempDir()); if (freespace != wxInvalidOffset) { if (static_cast<uint64>(freespace) < maxindex * PARTSIZE) { delete file; delete [] ba; return CONV_OUTOFDISKSPACE; } } // create new partmetfile, and remember the new name file->CreatePartFile(); newfilename = file->GetFullName(); Notify_ConvertUpdateProgress(8, _("Creating destination file")); file->m_hpartfile.SetLength( s_pfconverting->spaceneeded ); unsigned curindex = 0; CPath filename = finder.GetFirstFile(CDirIterator::File, filepartindex + wxT(".*.part")); while (filename.IsOk()) { // stats ++curindex; Notify_ConvertUpdateProgress(10 + (curindex * stepperpart), CFormat(_("Loading data from old download file (%u of %u)")) % curindex % partfilecount); long l; filename.GetFullName().RemoveExt().GetExt().ToLong(&l); fileindex = (unsigned)l; if (fileindex == 0) { filename = finder.GetNextFile(); continue; } uint32 chunkstart = (fileindex - 1) * PARTSIZE; // open, read data of the part-part-file into buffer, close file inputfile.Open(filename, CFile::read); uint64 toReadWrite = std::min<uint64>(PARTSIZE, inputfile.GetLength()); inputfile.Read(ba, toReadWrite); inputfile.Close(); Notify_ConvertUpdateProgress(10 + (curindex * stepperpart), CFormat(_("Saving data block into new single download file (%u of %u)")) % curindex % partfilecount); // write the buffered data file->m_hpartfile.WriteAt(ba, chunkstart, toReadWrite); filename = finder.GetNextFile(); } delete[] ba; } catch (const CSafeIOException& e) { AddDebugLogLineC(logPfConvert, wxT("IO error while converting partfiles: ") + e.what()); delete[] ba; file->Delete(); return CONV_IOERROR; } file->m_hpartfile.Close(); } // import an external common format partdownload else //if (pfconverting->partmettype==PMT_DEFAULTOLD || pfconverting->partmettype==PMT_NEWOLD || Shareaza ) { if (!s_pfconverting->removeSource) { wxMutexLocker lock(s_mutex); s_pfconverting->spaceneeded = oldfile.GetFileSize(); } Notify_ConvertUpdateJobInfo(s_pfconverting); sint64 freespace = CPath::GetFreeSpaceAt(thePrefs::GetTempDir()); if (freespace == wxInvalidOffset) { delete file; return CONV_IOERROR; } else if (freespace < s_pfconverting->spaceneeded) { delete file; return CONV_OUTOFDISKSPACE; } file->CreatePartFile(); newfilename = file->GetFullName(); file->m_hpartfile.Close(); bool ret = false; Notify_ConvertUpdateProgress(92, _("Copy")); CPath::RemoveFile(newfilename.RemoveExt()); if (!oldfile.FileExists()) { // data file does not exist. well, then create a 0 byte big one CFile datafile; ret = datafile.Create(newfilename.RemoveExt()); } else if (s_pfconverting->removeSource) { ret = CPath::RenameFile(oldfile, newfilename.RemoveExt()); } else { ret = CPath::CloneFile(oldfile, newfilename.RemoveExt(), false); } if (!ret) { file->Delete(); //delete file; return CONV_FAILED; } } Notify_ConvertUpdateProgress(94, _("Retrieving source downloadfile information")); CPath::RemoveFile(newfilename); if (s_pfconverting->removeSource) { CPath::RenameFile(folder.JoinPaths(partfile), newfilename); } else { CPath::CloneFile(folder.JoinPaths(partfile), newfilename, false); } file->m_hashlist.clear(); if (!file->LoadPartFile(thePrefs::GetTempDir(), file->GetPartMetFileName(), false)) { //delete file; file->Delete(); return CONV_BADFORMAT; } if (s_pfconverting->partmettype == PMT_NEWOLD || s_pfconverting->partmettype == PMT_SPLITTED) { file->SetCompletedSize(file->transferred); file->m_iGainDueToCompression = 0; file->m_iLostDueToCorruption = 0; } Notify_ConvertUpdateProgress(100, _("Adding download and saving new partfile")); theApp->downloadqueue->AddDownload(file, thePrefs::AddNewFilesPaused(), 0); file->SavePartFile(); if (file->GetStatus(true) == PS_READY) { theApp->sharedfiles->SafeAddKFile(file); // part files are always shared files } if (s_pfconverting->removeSource) { CPath oldFile = finder.GetFirstFile(CDirIterator::File, filepartindex + wxT(".*")); while (oldFile.IsOk()) { CPath::RemoveFile(folder.JoinPaths(oldFile)); oldFile = finder.GetNextFile(); } if (s_pfconverting->partmettype == PMT_SPLITTED) { CPath::RemoveDir(folder); } } return CONV_OK; }
// запустить через ShellExecuteEx в скрытом режиме // (см. шаманство с консолью) static BOOL ExecuteHide( CPath& path, DWORD* out_exitcode, CSimpleString* strOut ) { HANDLE hSaveStdin = NULL; HANDLE hSaveStdout = NULL; HANDLE hChildStdoutRdDup = NULL; HANDLE hChildStdoutWr = NULL; try { // подключаем консоль STARTUPINFOA si = { sizeof(STARTUPINFOA) }; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; PROCESS_INFORMATION pi = { 0 }; char command_line[] = "cmd"; ::CreateProcessA( NULL, // не используем имя файла, все в строке запуска command_line, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable TRUE, // Set handle inheritance to FALSE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // STARTUPINFO &pi ); // PROCESS_INFORMATION // задержка чтобы консоль успела создаться ::WaitForSingleObject( pi.hProcess, 100 ); BOOL hResult = FALSE; HMODULE hLib = LoadLibraryA("Kernel32.dll"); if ( hLib != NULL ) { typedef BOOL (STDAPICALLTYPE *ATTACHCONSOLE)( DWORD dwProcessId ); ATTACHCONSOLE _AttachConsole = NULL; _AttachConsole = (ATTACHCONSOLE)GetProcAddress( hLib, "AttachConsole" ); if ( _AttachConsole ) hResult = _AttachConsole( pi.dwProcessId ); FreeLibrary( hLib ); } if ( hResult == FALSE ) AllocConsole(); TerminateProcess( pi.hProcess, 0 ); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); HANDLE hChildStdinRd; HANDLE hChildStdinWr; HANDLE hChildStdinWrDup; HANDLE hChildStdoutRd; // Set the bInheritHandle flag so pipe handles are inherited. SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; BOOL fSuccess; // The steps for redirecting child process's STDOUT: // 1. Save current STDOUT, to be restored later. // 2. Create anonymous pipe to be STDOUT for child process. // 3. Set STDOUT of the parent process to be write handle to // the pipe, so it is inherited by the child process. // 4. Create a noninheritable duplicate of the read handle and // close the inheritable read handle. // Save the handle to the current STDOUT. hSaveStdout = GetStdHandle( STD_OUTPUT_HANDLE ); // Create a pipe for the child process's STDOUT. if ( !CreatePipe( &hChildStdoutRd, &hChildStdoutWr, &saAttr, 0 ) ) throw(1); // Set a write handle to the pipe to be STDOUT. if ( !SetStdHandle( STD_OUTPUT_HANDLE, hChildStdoutWr ) ) throw(1); // Create noninheritable read handle and close the inheritable read // handle. fSuccess = DuplicateHandle( GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS ); if( fSuccess == FALSE ) throw(1); CloseHandle( hChildStdoutRd ); // The steps for redirecting child process's STDIN: // 1. Save current STDIN, to be restored later. // 2. Create anonymous pipe to be STDIN for child process. // 3. Set STDIN of the parent to be the read handle to the // pipe, so it is inherited by the child process. // 4. Create a noninheritable duplicate of the write handle, // and close the inheritable write handle. // Save the handle to the current STDIN. hSaveStdin = GetStdHandle( STD_INPUT_HANDLE ); // Create a pipe for the child process's STDIN. if ( !CreatePipe( &hChildStdinRd, &hChildStdinWr, &saAttr, 0 ) ) throw(1); // Set a read handle to the pipe to be STDIN. if ( !SetStdHandle( STD_INPUT_HANDLE, hChildStdinRd ) ) throw(1); // Duplicate the write handle to the pipe so it is not inherited. fSuccess = DuplicateHandle( GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS ); if ( fSuccess == FALSE ) throw(1); CloseHandle( hChildStdinWr ); } catch (...) { return FALSE; } // Now create the child process. SHELLEXECUTEINFOA shinf = { sizeof(SHELLEXECUTEINFOA) }; shinf.lpFile = path.GetPath(); shinf.lpParameters = path.GetFileParams(); //shinf.lpDirectory = path.GetDirectory(); shinf.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS; shinf.nShow = SW_HIDE; BOOL bSuccess = ::ShellExecuteExA( &shinf ); if ( bSuccess && shinf.hInstApp <= (HINSTANCE)32 ) bSuccess = FALSE; HANDLE hProcess = shinf.hProcess; try { if ( bSuccess == FALSE || hProcess == NULL ) throw(1); if ( hChildStdoutWr != NULL ) { CloseHandle( hChildStdoutWr ); hChildStdoutWr = NULL; } // After process creation, restore the saved STDIN and STDOUT. if ( hSaveStdin != NULL ) { if ( !SetStdHandle( STD_INPUT_HANDLE, hSaveStdin ) ) throw(1); CloseHandle( hSaveStdin ); hSaveStdin = NULL; } if ( hSaveStdout != NULL ) { if ( !SetStdHandle( STD_OUTPUT_HANDLE, hSaveStdout ) ) throw(1); CloseHandle( hSaveStdout ); hSaveStdout = NULL; } if ( hChildStdoutRdDup != NULL ) { // Read output from the child process, and write to parent's STDOUT. const int BUFSIZE = 1024; DWORD dwRead; CMemBuffer< char, BUFSIZE > bufStr; // строковой буфер CMemBuffer< char, BUFSIZE > bufCmdLine; // строковой буфер for (;;) { if( ReadFile( hChildStdoutRdDup, bufCmdLine.GetBuffer(), BUFSIZE, &dwRead, NULL ) == FALSE || dwRead == 0 ) { DWORD exit_code = 0; if ( ::GetExitCodeProcess( hProcess, &exit_code ) == FALSE || exit_code != STILL_ACTIVE ) { break; } else { continue; } } bufCmdLine[ dwRead ] = '\0'; ::OemToAnsi( bufCmdLine.GetBuffer(), bufStr.GetBuffer() ); strOut->Append( bufStr.GetBuffer() ); } CloseHandle( hChildStdoutRdDup ); hChildStdoutRdDup = NULL; } FreeConsole(); } catch (...) { if ( hChildStdoutWr != NULL ) CloseHandle( hChildStdoutWr ); if ( hSaveStdin != NULL ) CloseHandle( hSaveStdin ); if ( hSaveStdout != NULL ) CloseHandle( hSaveStdout ); if ( hChildStdoutRdDup != NULL ) CloseHandle( hChildStdoutRdDup ); if ( bSuccess == FALSE || hProcess == NULL ) return FALSE; } ::GetExitCodeProcess( hProcess, out_exitcode ); CloseHandle( hProcess ); return TRUE; }
// запустить через CreateProcess в скрытом режиме static BOOL RunProcessHide( CPath& path, DWORD* out_exitcode, CSimpleString* strOut ) { static const int MAX_CMD = 1024; STARTUPINFOA si = { sizeof(STARTUPINFOA) }; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; // устанавливаем именованные каналы на потоки ввода/вывода BOOL bUsePipes = FALSE; HANDLE FWritePipe = NULL; HANDLE FReadPipe = NULL; SECURITY_ATTRIBUTES pa = { sizeof(pa), NULL, TRUE }; bUsePipes = ::CreatePipe( &FReadPipe, &FWritePipe, &pa, 0 ); if ( bUsePipes != FALSE ) { si.hStdOutput = FWritePipe; si.hStdInput = FReadPipe; si.hStdError = FWritePipe; si.dwFlags = STARTF_USESTDHANDLES | si.dwFlags; } // запускаем процесс CMemBuffer< char, MAX_CMD > bufCmdLine; // строковой буфер длиной MAX_CMD bufCmdLine.GetBuffer()[0] = 0; strcat( bufCmdLine.GetBuffer(), "\"" ); strcat( bufCmdLine.GetBuffer(), path.GetPath() ); strcat( bufCmdLine.GetBuffer(), "\"" ); if ( path.GetFileParams() != NULL ) { strcat( bufCmdLine.GetBuffer(), " " ); strcat( bufCmdLine.GetBuffer(), path.GetFileParams() ); } char *lp = NULL; if (strlen(currentDir) > 0) lp = currentDir; PROCESS_INFORMATION pi = { 0 }; BOOL RetCode = ::CreateProcessA( NULL, // не используем имя файла, все в строке запуска bufCmdLine.GetBuffer(), // строка запуска NULL, // Process handle not inheritable NULL, // Thread handle not inheritable TRUE, // Set handle inheritance to FALSE 0, // No creation flags NULL, // Use parent's environment block lp, //path.GetDirectory(), // устанавливаем дирректорию запуска &si, // STARTUPINFO &pi ); // PROCESS_INFORMATION // если провалили запуск сообщаем об ошибке if ( RetCode == FALSE ) { ::CloseHandle( FReadPipe ); ::CloseHandle( FWritePipe ); return FALSE; } // закрываем описатель потока, в нем нет необходимости ::CloseHandle( pi.hThread ); // ожидаем завершение работы процесса try { DWORD BytesToRead = 0; DWORD BytesRead = 0; DWORD TotalBytesAvail = 0; DWORD PipeReaded = 0; DWORD exit_code = 0; CMemBuffer< char, MAX_CMD > bufStr; // строковой буфер длиной MAX_CMD while ( ::PeekNamedPipe( FReadPipe, NULL, 0, &BytesRead, &TotalBytesAvail, NULL ) ) { if ( TotalBytesAvail == 0 ) { if ( ::GetExitCodeProcess( pi.hProcess, &exit_code ) == FALSE || exit_code != STILL_ACTIVE ) { break; } else { Sleep(10); continue; } } else { while ( TotalBytesAvail > BytesRead ) { if ( TotalBytesAvail - BytesRead > MAX_CMD - 1 ) { BytesToRead = MAX_CMD - 1; } else { BytesToRead = TotalBytesAvail - BytesRead; } if ( ::ReadFile( FReadPipe, bufCmdLine.GetBuffer(), BytesToRead, &PipeReaded, NULL ) == FALSE ) { break; } if ( PipeReaded <= 0 ) continue; BytesRead += PipeReaded; bufCmdLine[ PipeReaded ] = '\0'; ::OemToAnsi( bufCmdLine.GetBuffer(), bufStr.GetBuffer() ); strOut->Append( bufStr.GetBuffer() ); } } } } catch (...) { } // Код завершения процесса ::GetExitCodeProcess( pi.hProcess, out_exitcode ); ::CloseHandle( pi.hProcess ); ::CloseHandle( FReadPipe ); ::CloseHandle( FWritePipe ); return TRUE; }
static int exec( lua_State* L ) { // считываем запускаемую команду CPath file = luaL_checkstring( L, 1 ); const char* verb = lua_tostring( L, 2 ); int noshow = lua_toboolean( L, 3 ); int dowait = lua_toboolean( L, 4 ); BOOL useConsoleOut = dowait && noshow && ( verb == NULL ); DWORD exit_code = (DWORD)-1; BOOL bSuccess = FALSE; CSimpleString strOut; if ( useConsoleOut != FALSE ) { bSuccess = RunProcessHide( file, &exit_code, &strOut ) || ExecuteHide( file, &exit_code, &strOut ); } else { HANDLE hProcess = NULL; // запускаем процесс if ( verb != NULL && // если есть команда запуска strcmp( verb, "explore" ) == 0 && // если команда запуска explore CPath::IsFileExists( file.GetPath() ) ) // проверяем файл ли это { SHELLEXECUTEINFOA shinf = { sizeof(SHELLEXECUTEINFOA) }; shinf.lpFile = "explorer.exe"; CSimpleString sFileParams; sFileParams.Append( "/e, /select," ); sFileParams.Append( file.GetPath() ); shinf.lpParameters = sFileParams.GetString(); shinf.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS; shinf.nShow = noshow ? SW_HIDE : SW_SHOWNORMAL; bSuccess = ::ShellExecuteExA( &shinf ); if ( bSuccess && shinf.hInstApp <= (HINSTANCE)32 ) bSuccess = FALSE; hProcess = shinf.hProcess; } else if ( verb != NULL && // если есть команда запуска strcmp( verb, "select" ) == 0 && // если команда запуска select CPath::IsPathExist( file.GetPath() ) ) // проверяем правильный путь { SHELLEXECUTEINFOA shinf = { sizeof(SHELLEXECUTEINFOA) }; shinf.lpFile = "explorer.exe"; CSimpleString sFileParams; sFileParams.Append( "/select," ); sFileParams.Append( file.GetPath() ); shinf.lpParameters = sFileParams.GetString(); shinf.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS; shinf.nShow = noshow ? SW_HIDE : SW_SHOWNORMAL; bSuccess = ::ShellExecuteExA( &shinf ); if ( bSuccess && shinf.hInstApp <= (HINSTANCE)32 ) bSuccess = FALSE; hProcess = shinf.hProcess; } else { SHELLEXECUTEINFOA shinf = { sizeof(SHELLEXECUTEINFOA) }; shinf.lpFile = file.GetPath(); shinf.lpParameters = file.GetFileParams(); shinf.lpVerb = verb; if (strlen(currentDir) > 3) { shinf.lpDirectory = currentDir; } shinf.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_DDEWAIT; if ( verb == NULL ) { shinf.fMask |= SEE_MASK_NOCLOSEPROCESS; } else { shinf.fMask |= SEE_MASK_INVOKEIDLIST; } shinf.nShow = noshow ? SW_HIDE : SW_SHOWNORMAL; bSuccess = ::ShellExecuteExA( &shinf ); if ( bSuccess && shinf.hInstApp <= (HINSTANCE)32 ) bSuccess = FALSE; hProcess = shinf.hProcess; } if ( dowait != FALSE && hProcess != NULL ) { // ждем пока процесс не завершится ::WaitForSingleObject( hProcess, INFINITE ); } if ( hProcess != NULL ) { if ( dowait != FALSE ) ::GetExitCodeProcess( hProcess, &exit_code ); CloseHandle( hProcess ); } if ( bSuccess != FALSE ) { ::SetLastError( 0 ); DWORD dw; int len; char* lpMsgBuf = GetLastErrorString( &dw, &len ); strOut.Append( lpMsgBuf ); ::LocalFree( lpMsgBuf ); } } if ( bSuccess == FALSE ) { lua_pushboolean( L, FALSE ); lua_pushlasterr( L, NULL ); } else { exit_code != (DWORD)-1 ? lua_pushnumber( L, exit_code ) : lua_pushboolean( L, TRUE ); lua_pushstring( L, strOut.GetString() ); } return 2; }