| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * Module: rbutil |
| * File: rbutil.cpp |
| * |
| * Copyright (C) 2005 Christi Alice Scarborough |
| * |
| * All files in this archive are subject to the GNU General Public License. |
| * See the file COPYING in the source tree root for full license agreement. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #include "rbutil.h" |
| #include "installlog.h" |
| |
| /* this function gets a Bitmap from embedded memory */ |
| wxBitmap wxGetBitmapFromMemory(const unsigned char *data,int length) |
| { |
| wxMemoryInputStream istream( data,length); |
| return wxBitmap(wxImage(istream, wxBITMAP_TYPE_ANY, -1), -1); |
| } |
| |
| // This class allows us to return directories as well as files to |
| // wxDir::Traverse |
| class wxDirTraverserIncludeDirs : public wxDirTraverser |
| { |
| public: |
| wxDirTraverserIncludeDirs(wxArrayString& files) : m_files(files) { } |
| |
| virtual wxDirTraverseResult OnFile(const wxString& filename) |
| { |
| m_files.Add(filename); |
| return wxDIR_CONTINUE; |
| } |
| |
| virtual wxDirTraverseResult OnDir(const wxString& dirname) |
| { |
| m_files.Add(dirname); |
| return wxDIR_CONTINUE; |
| } |
| |
| private: |
| wxArrayString& m_files; |
| }; |
| |
| wxDEFINE_SCOPED_PTR_TYPE(wxZipEntry); |
| |
| const wxChar* _rootmatch[] = { |
| wxT("rockbox.*"), |
| wxT("ajbrec.ajz"), |
| wxT("archos.mod"), |
| wxT(".scrobbler.*"), |
| wxT("battery_bench.txt"), |
| wxT("battery.dummy"), |
| }; |
| const wxArrayString* rootmatch = new wxArrayString( |
| (size_t) (sizeof(_rootmatch) / sizeof(wxChar*)), _rootmatch); |
| |
| bool InstallTheme(wxString Themesrc) |
| { |
| wxString dest,src,err; |
| |
| int pos = Themesrc.Find('/',true); |
| wxString themename = Themesrc.SubString(pos+1,Themesrc.Length()); |
| |
| src = gv->themes_url + wxT("/") + Themesrc; |
| dest = gv->stdpaths->GetUserDataDir() |
| + wxT("" PATH_SEP "download" PATH_SEP) + themename; |
| if( DownloadURL(src, dest) ) |
| { |
| wxRemoveFile(dest); |
| ERR_DIALOG(wxT("Unable to download ") + src, wxT("Install Theme")); |
| return false; |
| } |
| |
| if(!checkZip(dest)) |
| { |
| ERR_DIALOG(wxT("The Zip ") + dest |
| + wxT(" does not contain the correct dir structure"), |
| wxT("Install Theme")); |
| return false; |
| } |
| |
| if(UnzipFile(dest,gv->curdestdir, true)) |
| { |
| ERR_DIALOG(wxT("Unable to unzip ") + dest + wxT(" to ") |
| + gv->curdestdir, wxT("Install Theme")); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool checkZip(wxString zipname) |
| { |
| |
| wxZipEntryPtr entry; |
| |
| wxFFileInputStream* in_file = new wxFFileInputStream(zipname); |
| wxZipInputStream* in_zip = new wxZipInputStream(*in_file); |
| |
| entry.reset(in_zip->GetNextEntry()); |
| |
| wxString name = entry->GetName(); |
| if(entry->IsDir()) |
| { |
| if( 0==name.Cmp(wxT(".rockbox")) |
| || 0==name.Cmp(wxT(".rockbox\\")) |
| || 0==name.Cmp(wxT(".rockbox/")) ) |
| return true; |
| } |
| else |
| { |
| if( name.StartsWith(wxT(".rockbox/")) |
| || name.StartsWith(wxT(".rockbox\\")) ) |
| return true; |
| } |
| |
| return false; |
| |
| } |
| |
| int DownloadURL(wxString src, wxString dest) |
| { |
| int input, errnum = 0, success = false; |
| wxString buf, errstr; |
| wxLogVerbose(wxT("=== begin DownloadURL(%s,%s)"), src.c_str(), |
| dest.c_str()); |
| |
| buf = wxT("Fetching ") + src; |
| wxProgressDialog* progress = new wxProgressDialog(wxT("Downloading"), |
| buf, 100, NULL, wxPD_APP_MODAL | |
| wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME | |
| wxPD_REMAINING_TIME | wxPD_CAN_ABORT); |
| progress->SetSize(500,200); |
| progress->Update(0); |
| |
| |
| input = true; |
| wxURL* in_http = new wxURL(src); |
| |
| if(gv->proxy_url != wxT("")) |
| in_http->SetProxy(gv->proxy_url); |
| |
| if (in_http->GetError() == wxURL_NOERR) |
| { |
| |
| wxFFileOutputStream* os = new wxFFileOutputStream(dest); |
| input = false; |
| if (os->IsOk()) |
| { |
| wxInputStream* is = in_http->GetInputStream(); |
| input = true; |
| if (is) |
| { |
| size_t filesize = is->GetSize(); |
| input = true; |
| if (is->IsOk()) |
| { |
| char buffer[FILE_BUFFER_SIZE + 1]; |
| size_t current = 0; |
| |
| while (! is->Eof()) |
| { |
| is->Read(buffer, FILE_BUFFER_SIZE); |
| input = true; |
| if (is->LastRead() ) |
| { |
| os->Write(buffer, is->LastRead()); |
| input = false; |
| if (os->IsOk()) |
| { |
| current += os->LastWrite(); |
| if (!progress->Update(current * 100 / filesize)) |
| { |
| errstr = wxT("Download aborted by user"); |
| errnum = 1000; |
| break; |
| } |
| |
| } else |
| { |
| errnum = os->GetLastError(); |
| errstr = wxT("Can't write to output stream (") |
| + stream_err_str(errnum) + wxT(")"); |
| |
| break; |
| } |
| |
| } else |
| { |
| errnum = is->GetLastError(); |
| if (errnum == wxSTREAM_EOF) |
| { |
| errnum = 0; |
| break; |
| } |
| errstr = wxT("Can't read from input stream (") |
| + stream_err_str(errnum) + wxT(")"); |
| } |
| } |
| |
| os->Close(); |
| if (! errnum) |
| { |
| errnum = os->GetLastError(); |
| errstr = wxT("Can't close output file (") |
| + stream_err_str(errnum) + wxT(")"); |
| |
| input = false; |
| } |
| |
| if (! errnum) success = true; |
| |
| } else |
| { |
| errnum = is->GetLastError(); |
| errstr = wxT("Can't get input stream size (") |
| + stream_err_str(errnum) + wxT(")"); |
| } |
| } else |
| { |
| errnum = in_http->GetError(); |
| errstr.Printf(wxT("Can't get input stream (%d)"), errnum); |
| } |
| delete is; |
| } else |
| { |
| errnum = os->GetLastError(); |
| errstr = wxT("Can't create output stream (") |
| + stream_err_str(errnum) + wxT(")"); |
| } |
| delete os; |
| } else |
| { |
| errstr.Printf(wxT("Can't open URL %s (%d)"), src.c_str(), |
| in_http->GetError() ); |
| errnum = 100; |
| } |
| |
| delete in_http; |
| delete progress; |
| |
| if (!success) |
| { |
| if (errnum == 0) errnum = 999; |
| if (input) |
| { |
| ERR_DIALOG(errstr + wxT(" reading\n") + src, wxT("Download URL")); |
| } else |
| { |
| ERR_DIALOG(errstr + wxT("writing to download\n/") + dest, |
| wxT("Download URL")); |
| } |
| |
| } |
| |
| wxLogVerbose(wxT("=== end DownloadURL")); |
| return errnum; |
| } |
| |
| int UnzipFile(wxString src, wxString destdir, bool isInstall) |
| { |
| |
| wxZipEntryPtr entry; |
| wxString in_str, progress_msg, buf,subdir; |
| int errnum = 0, curfile = 0, totalfiles = 0; |
| InstallLog* log = NULL; |
| |
| wxLogVerbose(wxT("===begin UnzipFile(%s,%s,%i)"), |
| src.c_str(), destdir.c_str(), isInstall); |
| |
| wxFFileInputStream* in_file = new wxFFileInputStream(src); |
| wxZipInputStream* in_zip = new wxZipInputStream(*in_file); |
| if (in_file->Ok() ) |
| { |
| if (! in_zip->IsOk() ) |
| { |
| errnum = in_zip->GetLastError(); |
| ERR_DIALOG(wxT("Can't open ZIP stream ") + src |
| + wxT(" for reading (") + stream_err_str(errnum) |
| + wxT(")"), wxT("Unzip File") ); |
| delete in_zip; |
| delete in_file; |
| return true; |
| } |
| |
| totalfiles = in_zip->GetTotalEntries(); |
| if (! in_zip->IsOk() ) |
| { |
| errnum = in_zip->GetLastError(); |
| ERR_DIALOG( wxT("Error Getting total ZIP entries for ") |
| + src + wxT(" (") + stream_err_str(errnum) + wxT(")"), |
| wxT("Unzip File") ); |
| delete in_zip; |
| delete in_file; |
| return true; |
| } |
| } else |
| { |
| errnum = in_file->GetLastError(); |
| ERR_DIALOG(wxT("Can't open ") + src + wxT(" (") |
| + stream_err_str(errnum) + wxT(")"), wxT("Unzip File") ); |
| delete in_zip; |
| delete in_file; |
| return true; |
| } |
| |
| wxProgressDialog* progress = new wxProgressDialog(wxT("Unpacking archive"), |
| wxT("Preparing to unpack the downloaded files to your audio" |
| "device"), totalfiles, NULL, wxPD_APP_MODAL | |
| wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME | |
| wxPD_REMAINING_TIME | wxPD_CAN_ABORT); |
| progress->Update(0); |
| |
| // We're not overly worried if the logging fails |
| if (isInstall) |
| { |
| log = new InstallLog(destdir + wxT("" PATH_SEP UNINSTALL_FILE)); |
| } |
| |
| while (! errnum && |
| (entry.reset(in_zip->GetNextEntry()), entry.get() != NULL) ) |
| { |
| |
| |
| curfile++; |
| wxString name = entry->GetName(); |
| // set progress |
| progress_msg = wxT("Unpacking ") + name; |
| if (! progress->Update(curfile, progress_msg) ) |
| { |
| MESG_DIALOG(wxT("Unpacking cancelled by user")); |
| errnum = 1000; |
| break; |
| } |
| |
| in_str = destdir + wxT("" PATH_SEP) + name; |
| |
| subdir = wxPathOnly(in_str); |
| if(!(wxDirExists(subdir))) |
| { |
| if (! wxMkdir(subdir, 0777) ) |
| { |
| buf = wxT("Unable to create directory ") + subdir; |
| errnum = 100; |
| break; |
| } |
| log->WriteFile(subdir, true); // Directory |
| } |
| |
| if(entry->IsDir()) |
| { |
| if(!wxDirExists(name)) |
| { |
| if(!wxMkdir(name, 0777) ) |
| { |
| buf = wxT("Unable to create directory ") + name; |
| errnum = 100; |
| break; |
| } |
| } |
| log->WriteFile(name, true); // Directory |
| continue; // this is just a directory, nothing else to do |
| } |
| |
| // its a file, copy it |
| wxFFileOutputStream* out = new wxFFileOutputStream(in_str); |
| if (! out->IsOk() ) |
| { |
| buf = wxT("Can't open file ") + in_str + wxT(" for writing"); |
| delete out; |
| errnum = 100; |
| break; |
| } else if (isInstall) |
| { |
| log->WriteFile(name); |
| } |
| |
| in_zip->Read(*out); |
| if (! out->IsOk()) { |
| buf.Printf(wxT("Can't write to %s (%d)"), in_str.c_str(), |
| errnum = out->GetLastError() ); |
| } |
| |
| if (!in_zip->IsOk() && ! in_file->GetLastError() == wxSTREAM_EOF) |
| { |
| buf.Printf(wxT("Can't read from %s (%d)"), src.c_str(), |
| errnum = in_file->GetLastError() ); |
| } |
| |
| if (! out->Close() && errnum == 0) |
| { |
| buf.Printf(wxT("Unable to close %s (%d)"), in_str.c_str(), |
| errnum = out->GetLastError() ); |
| |
| } |
| |
| delete out; |
| |
| } |
| |
| delete in_zip; delete in_file; delete progress; |
| |
| if (errnum) |
| { |
| ERR_DIALOG(buf, wxT("Unzip File")); |
| } |
| |
| if (log) delete log; |
| wxLogVerbose(wxT("=== end UnzipFile")); |
| return(errnum); |
| |
| } |
| |
| int Uninstall(const wxString dir, bool isFullUninstall) { |
| wxString buf, uninst; |
| unsigned int i; |
| bool errflag = false; |
| InstallLog *log = NULL; |
| wxArrayString* FilesToRemove = NULL; |
| |
| wxLogVerbose(wxT("=== begin Uninstall(%s,%i)"), dir.c_str(), isFullUninstall); |
| |
| wxProgressDialog* progress = new wxProgressDialog(wxT("Uninstalling"), |
| wxT("Reading uninstall data from jukebox"), 100, NULL, |
| wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH | |
| wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT); |
| progress->Update(0); |
| |
| if (! isFullUninstall) |
| { |
| |
| buf = dir + wxT("" PATH_SEP UNINSTALL_FILE); |
| log = new InstallLog(buf, false); // Don't create the log |
| FilesToRemove = log->GetInstalledFiles(); |
| if (log) delete log; |
| |
| if (FilesToRemove == NULL || FilesToRemove->GetCount() < 1) { |
| wxLogNull lognull; |
| if ( wxMessageDialog(NULL, |
| wxT("Rockbox Utility can't find any uninstall data on this " |
| "jukebox.\n" |
| "Would you like to attempt a full uninstall?\n" |
| "(WARNING: A full uninstall removes all files in your Rockbox " |
| "folder)"), |
| wxT("Standard uninstall not possible"), |
| wxICON_EXCLAMATION | wxYES_NO | wxNO_DEFAULT).ShowModal() |
| == wxID_YES) |
| { |
| isFullUninstall = true; |
| } |
| else { |
| MESG_DIALOG(wxT("Uninstall cancelled by user")); |
| delete progress; |
| return 1000; |
| } |
| } |
| } |
| |
| if (isFullUninstall ) |
| { |
| buf = dir + wxT("" PATH_SEP ".rockbox"); |
| if (rm_rf(buf) ) |
| { |
| WARN_DIALOG(wxT("Unable to completely remove Rockbox directory"), |
| wxT("Full uninstall") ); |
| errflag = true; |
| } |
| |
| wxDir* root = new wxDir(dir); |
| wxArrayString* special = new wxArrayString(); |
| // Search for files for deletion in the jukebox root |
| for (i = 0; i < rootmatch->GetCount(); i++) |
| { |
| const wxString match = (*rootmatch)[i]; |
| root->GetAllFiles(dir, special, match, wxDIR_FILES); |
| } |
| delete root; |
| |
| // Sort in reverse order so we get directories last |
| special->Sort(true); |
| |
| for (i = 0; i < special->GetCount(); i++) |
| { |
| |
| if (wxDirExists((*special)[i]) ) |
| { |
| // We don't check the return code since we don't want non |
| // empty dirs disappearing. |
| wxRmdir((*special)[i]); |
| |
| } else if (wxFileExists((*special)[i]) ) |
| { |
| if (! wxRemoveFile((*special)[i]) ) |
| { |
| WARN_DIALOG(wxT("Can't delete ") + (*special)[i], |
| wxT("Full uninstall")); |
| errflag = true; |
| } |
| } |
| // Otherwise there isn't anything there, so we don't have to worry. |
| } |
| delete special; |
| } else |
| { |
| wxString instplat, this_path_sep; |
| unsigned int totalfiles, rc; |
| totalfiles = FilesToRemove->GetCount(); |
| FilesToRemove->Sort(true); // Reverse alphabetical ie dirs after files |
| |
| for (i = 0; i < totalfiles; i++) |
| { |
| // If we're running on the device, let's not delete our own |
| // installation, eh? |
| if (gv->portable && |
| FilesToRemove->Item(i).StartsWith(PATH_SEP |
| wxT("RockboxUtility")) ) |
| { |
| continue; |
| } |
| |
| wxString* buf2 = new wxString; |
| buf = dir + FilesToRemove->Item(i); |
| buf2->Format(wxT("Deleting %s"), buf.c_str()); |
| |
| if (! progress->Update((i + 1) * 100 / totalfiles, *buf2) ) |
| { |
| WARN_DIALOG(wxT("Cancelled by user"), wxT("Normal Uninstall")); |
| delete progress; |
| return true; |
| } |
| |
| if (wxDirExists(buf) ) |
| { |
| // If we're about to attempt to remove .rockbox. delete |
| // install data first |
| *buf2 = dir + wxT("" PATH_SEP ".rockbox"); |
| if ( buf.IsSameAs(buf2->c_str()) ) |
| { |
| *buf2 = dir +wxT("" PATH_SEP UNINSTALL_FILE); |
| wxRemoveFile(*buf2); |
| } |
| |
| if ( (rc = ! wxRmdir(buf)) ) |
| { |
| buf = buf.Format(wxT("Can't remove directory %s"), |
| buf.c_str()); |
| errflag = true; |
| WARN_DIALOG(buf.c_str(), wxT("Standard uninstall")); |
| } |
| } else if (wxFileExists(buf) ) |
| { |
| if ( (rc = ! wxRemoveFile(buf)) ) |
| { |
| buf = buf.Format(wxT("Can't delete file %s"), |
| buf.c_str()); |
| errflag = true; |
| WARN_DIALOG(buf.c_str(), wxT("Standard uninstall")); |
| } |
| } else |
| { |
| errflag = true; |
| buf = buf.Format(wxT("Can't find file or directory %s"), |
| buf.c_str() ); |
| WARN_DIALOG(buf.c_str(), wxT("Standard uninstall") ); |
| } |
| |
| uninst = uninst.AfterFirst('\n'); |
| } |
| if (errflag) |
| { |
| ERR_DIALOG(wxT("Unable to remove some files"), |
| wxT("Standard uninstall")) ; |
| } |
| |
| if (FilesToRemove != NULL) delete FilesToRemove; |
| } |
| |
| delete progress; |
| wxLogVerbose(wxT("=== end Uninstall")); |
| return errflag; |
| } |
| |
| |
| wxString stream_err_str(int errnum) |
| { |
| wxString out; |
| |
| switch (errnum) { |
| case wxSTREAM_NO_ERROR: |
| out = wxT("wxSTREAM_NO_ERROR"); |
| break; |
| case wxSTREAM_EOF: |
| out = wxT("wxSTREAM_EOF"); |
| break; |
| case wxSTREAM_WRITE_ERROR: |
| out = wxT("wxSTREAM_WRITE_ERROR"); |
| break; |
| case wxSTREAM_READ_ERROR: |
| out = wxT("wxSTREAM_READ_ERROR"); |
| break; |
| default: |
| out = wxT("UNKNOWN"); |
| break; |
| } |
| return out; |
| } |
| |
| bool InstallRbutil(wxString dest) |
| { |
| wxArrayString filestocopy; |
| wxString str, buf, dstr, localpath, destdir; |
| unsigned int i; |
| wxDir dir; |
| bool copied_exe = false, made_rbdir = false; |
| InstallLog* log; |
| |
| buf = dest + wxT("" PATH_SEP ".rockbox"); |
| |
| if (! wxDirExists(buf) ) |
| { |
| wxMkdir(buf); |
| made_rbdir = true; |
| } |
| |
| buf = dest + wxT("" PATH_SEP UNINSTALL_FILE); |
| log = new InstallLog(buf); |
| if (made_rbdir) log->WriteFile(wxT(".rockbox"), true); |
| |
| destdir = dest + wxT("" PATH_SEP "RockboxUtility"); |
| if (! wxDirExists(destdir) ) |
| { |
| if (! wxMkdir(destdir, 0777) ) |
| { |
| WARN_DIALOG( wxT("Unable to create directory for installer (") |
| + destdir + wxT(")"), wxT("Portable install") ); |
| return false; |
| } |
| log->WriteFile(wxT("RockboxUtility"), true); |
| } |
| |
| dir.GetAllFiles(gv->ResourceDir, &filestocopy, wxT("*"), |
| wxDIR_FILES); |
| if (filestocopy.GetCount() < 1) |
| { |
| WARN_DIALOG(wxT("No files to copy"), wxT("Portable install") ); |
| return false; |
| } |
| |
| // Copy the contents of the program directory |
| for (i = 0; i < filestocopy.GetCount(); i++) |
| { |
| if (filestocopy[i].AfterLast(PATH_SEP_CHR) == EXE_NAME) |
| { |
| copied_exe = true; |
| } |
| |
| dstr = destdir + wxT("" PATH_SEP) |
| + filestocopy[i].AfterLast(PATH_SEP_CHR); |
| if (! wxCopyFile(filestocopy[i], dstr) ) |
| { |
| WARN_DIALOG( wxT("Error copying file (") |
| + filestocopy[i].c_str() + wxT(" -> ") |
| + dstr + wxT(")"), wxT("Portable Install") ); |
| return false; |
| } |
| buf = dstr; |
| buf.Replace(dest, wxEmptyString, false); |
| log->WriteFile(buf); |
| } |
| |
| if (! copied_exe) |
| { |
| str = gv->AppDir + wxT("" PATH_SEP EXE_NAME); |
| dstr = destdir + wxT("" PATH_SEP EXE_NAME); |
| if (! wxCopyFile(str, dstr) ) |
| { |
| WARN_DIALOG(wxT("Can't copy program binary ") |
| + str + wxT(" -> ") + dstr, wxT("Portable Install") ); |
| return false; |
| } |
| buf = dstr; |
| buf.Replace(dest, wxEmptyString, false); |
| log->WriteFile(buf); |
| } |
| |
| // Copy the local ini file so that it knows that it's a portable copy |
| gv->UserConfig->Flush(); |
| dstr = destdir + wxT("" PATH_SEP "RockboxUtility.cfg"); |
| if (! wxCopyFile(gv->UserConfigFile, dstr) ) |
| { |
| WARN_DIALOG(wxT("Unable to install user config file (") |
| + gv->UserConfigFile + wxT(" -> ") + dstr + wxT(")"), |
| wxT("Portable Install") ); |
| return false; |
| } |
| buf = dstr; |
| buf.Replace(dest, wxEmptyString, false); |
| log->WriteFile(buf); |
| |
| delete log; |
| return true; |
| } |
| |
| bool rm_rf(wxString file) |
| { |
| wxLogVerbose(wxT("=== begin rm-rf(%s)"), file.c_str() ); |
| |
| wxString buf; |
| wxArrayString selected; |
| wxDirTraverserIncludeDirs wxdtid(selected); |
| unsigned int rc = 0, i; |
| bool errflag = false; |
| |
| if (wxFileExists(file) ) |
| { |
| rc = ! wxRemoveFile(file); |
| } else if (wxDirExists(file) ) |
| { |
| wxDir* dir = new wxDir(file);; |
| dir->Traverse(wxdtid); |
| delete dir; |
| // Sort into reverse alphabetical order for deletion in correct order |
| // (directories after files) |
| selected.Sort(true); |
| selected.Add(file); |
| |
| wxProgressDialog* progress = new wxProgressDialog(wxT("Removing files"), |
| wxT("Deleting files"), selected.GetCount(), NULL, |
| wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH | |
| wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT); |
| |
| for (i = 0; i < selected.GetCount(); i++) |
| { |
| wxLogVerbose(selected[i]); |
| if (progress != NULL) |
| { |
| buf = wxT("Deleting ") + selected[i]; |
| if (! progress->Update(i, buf)) |
| { |
| WARN_DIALOG(wxT("Cancelled by user"), wxT("Erase Files")); |
| delete progress; |
| return true; |
| } |
| } |
| |
| if (wxDirExists(selected[i]) ) |
| { |
| if ((rc = ! wxRmdir(selected[i])) ) |
| { |
| errflag = true; |
| WARN_DIALOG(wxT("Can't remove directory ") + selected[i], |
| wxT("Erase files")); |
| } |
| } else if ((rc = ! wxRemoveFile(selected[i])) ) |
| { |
| errflag = true; |
| WARN_DIALOG(wxT("Error deleting file ") + selected[i], |
| wxT("Erase files")); |
| } |
| } |
| delete progress; |
| } else |
| { |
| WARN_DIALOG(wxT("Can't find expected file ") + file, |
| wxT("Erase files")); |
| return true; |
| } |
| |
| wxLogVerbose(wxT("=== end rm-rf")); |
| return rc ? true : false; |
| } |
| |
| |