Example #1
0
int DirManager::ProjectFSCK(bool forceerror, bool silentlycorrect)
{
      
   // get a rough guess of how many blockfiles will be found/processed
   // at each step by looking at the size of the blockfile hash
   int blockcount=blockFileHash.size();
   int ret=0;
   int ndx;

   // enumerate *all* files in the project directory
   wxArrayString fnameList;

   wxArrayString orphanList;
   BlockHash    missingAliasList;
   BlockHash    missingAliasFiles;
   BlockHash    missingSummaryList;
   BlockHash    missingDataList;

   // this function is finally a misnomer
   rm_dash_rf_enumerate_prompt((projFull != wxT("")? projFull: mytemp),
                               fnameList,wxEmptyString,1,0,blockcount,
                               _("Inspecting project file data..."));
   
   // enumerate orphaned blockfiles
   BlockHash diskFileHash;
   for(ndx=0;ndx<(int)fnameList.GetCount();ndx++){
      wxFileName fullname = fnameList[ndx];
      wxString basename=fullname.GetName();
      
      diskFileHash[basename.c_str()]=0; // just needs to be defined
      if(blockFileHash.find(basename) == blockFileHash.end()){
         // the blockfile on disk is orphaned
         orphanList.Add(fullname.GetFullPath());
         if (!silentlycorrect)
            wxLogWarning(_("Orphaned blockfile: (%s)"),
                         fullname.GetFullPath().c_str());
      }
   }
   
   // enumerate missing alias files
   BlockHash::iterator i=blockFileHash.begin();
   while(i != blockFileHash.end()) {
      wxString key=i->first;
      BlockFile *b=i->second;
      
      if(b->IsAlias()){
         wxFileName aliasfile=((AliasBlockFile *)b)->GetAliasedFile();
         if(aliasfile.GetFullPath()!=wxEmptyString && !wxFileExists(aliasfile.GetFullPath())){
            missingAliasList[key]=b;
            missingAliasFiles[aliasfile.GetFullPath().c_str()]=0; // simply must be defined
         }
      }
      i++;
   }

   if (!silentlycorrect) {
      i=missingAliasFiles.begin();
      while(i != missingAliasFiles.end()) {
         wxString key=i->first;
         wxLogWarning(_("Missing alias file: (%s)"),key.c_str());
         i++;
      }
   }

   // enumerate missing summary blockfiles
   i=blockFileHash.begin();
   while(i != blockFileHash.end()) {
      wxString key=i->first;
      BlockFile *b=i->second;
      
      if(b->IsAlias()){
         /* don't look in hash; that might find files the user moved
            that the Blockfile abstraction can't find itself */
         wxFileName file=MakeBlockFilePath(key);
         file.SetName(key);
         file.SetExt(wxT("auf"));
         if(!wxFileExists(file.GetFullPath().c_str())){
            missingSummaryList[key]=b;
            if (!silentlycorrect)
               wxLogWarning(_("Missing summary file: (%s.auf)"),
                            key.c_str());
         }
      }
      i++;
   }

   // enumerate missing data blockfiles
   i=blockFileHash.begin();
   while(i != blockFileHash.end()) {
      wxString key=i->first;
      BlockFile *b=i->second;

      if(!b->IsAlias()){
         wxFileName file=MakeBlockFilePath(key);
         file.SetName(key);
         file.SetExt(wxT("au"));
         if(!wxFileExists(file.GetFullPath().c_str())){
            missingDataList[key]=b;
            if (!silentlycorrect)
               wxLogWarning(_("Missing data file: (%s.au)"),
                            key.c_str());
         }
      }
      i++;
   }
   
   // First, pop the log so the user can see what be up.
   if(forceerror ||
      (!orphanList.IsEmpty() ||
      !missingAliasList.empty() ||
      !missingDataList.empty() ||
      !missingSummaryList.empty()) && !silentlycorrect){

      wxLogWarning(_("Project check found inconsistencies inspecting the loaded project data;\nclick 'Details' for a complete list of errors, or 'OK' to proceed to more options."));
      
      wxLog::GetActiveTarget()->Flush(); // Flush is both modal
      // (desired) and will clear the log (desired)
   }

   // report, take action
   // If in "silently correct" mode, leave orphaned blockfiles alone
   // (they will be deleted when project is saved the first time)
   if(!orphanList.IsEmpty() && !silentlycorrect){

      wxString promptA =
         _("Project check found %d orphaned blockfile[s]. These files are\nunused and probably left over from a crash or some other bug.\nThey should be deleted to avoid disk contention.");
      wxString prompt;
      
      prompt.Printf(promptA,(int)orphanList.GetCount());
      
      const wxChar *buttons[]={_("Delete orphaned files [safe and recommended]"),
                               _("Continue without deleting; silently work around the extra files"),
                               _("Close project immediately with no changes"),NULL};
      int action = ShowMultiDialog(prompt,
                                   _("Warning"),
                                   buttons);

      if(action==2)return (ret | FSCKstatus_CLOSEREQ);

      if(action==0){
         ret |= FSCKstatus_CHANGED;
         for(ndx=0;ndx<(int)orphanList.GetCount();ndx++){
            wxRemoveFile(orphanList[ndx]);
         }
      }
   }


   // Deal with any missing aliases
   if(!missingAliasList.empty()){
      int action;
      
      if (silentlycorrect)
      {
         // In "silently correct" mode, we always create silent blocks. This
         // makes sure the project is complete even if we open it again.
         action = 0;
      } else
      {
         wxString promptA =
            _("Project check detected %d input file[s] being used in place\n('alias files') are now missing.  There is no way for Audacity\nto recover these files automatically; you may choose to\npermanently fill in silence for the missing files, temporarily\nfill in silence for this session only, or close the project now\nand try to restore the missing files by hand.");
         wxString prompt;
      
         prompt.Printf(promptA,missingAliasFiles.size());
      
         const wxChar *buttons[]={_("Replace missing data with silence [permanent upon save]"),
                                  _("Temporarily replace missing data with silence [this session only]"),
                                  _("Close project immediately with no further changes"),NULL};
         action = ShowMultiDialog(prompt,
                                      _("Warning"),
                                      buttons);

         if(action==2)return (ret | FSCKstatus_CLOSEREQ);
      }

      BlockHash::iterator i=missingAliasList.begin();
      while(i != missingAliasList.end()) {
         AliasBlockFile *b = (AliasBlockFile *)i->second; //this is
         //safe, we checked that it's an alias block file earlier
         
         if(action==0){
            // silence the blockfiles by yanking the filename
            wxFileName dummy;
            dummy.Clear();
            b->ChangeAliasedFile(dummy);
            b->Recover();
            ret |= FSCKstatus_CHANGED;
         }else if(action==1){
            // silence the log for this session
            b->SilenceAliasLog();
         }
         i++;
      }
   }

   // Summary regeneration must happen after alias checking.
   if(!missingSummaryList.empty()){
      int action;
      
      if (silentlycorrect)
      {
         // In "silently correct" mode we just recreate the summary files
         action = 0;
      } else
      {
         wxString promptA =
            _("Project check detected %d missing summary file[s] (.auf).\nAudacity can fully regenerate these summary files from the\noriginal audio data in the project.");
         wxString prompt;
      
         prompt.Printf(promptA,missingSummaryList.size());
      
         const wxChar *buttons[]={_("Regenerate summary files [safe and recommended]"),
                                 _("Fill in silence for missing display data [this session only]"),
                                  _("Close project immediately with no further changes"),NULL};
         action = ShowMultiDialog(prompt,
                                      _("Warning"),
                                      buttons);
                                      
         if(action==2)return (ret | FSCKstatus_CLOSEREQ);
      }
      
      BlockHash::iterator i=missingSummaryList.begin();
      while(i != missingSummaryList.end()) {
         BlockFile *b = i->second;
         if(action==0){
            //regenerate from data
            b->Recover();
            ret |= FSCKstatus_CHANGED;
         }else if (action==1){
            b->SilenceLog();
         }
         i++;
      }
   }

   // Deal with any missing SimpleBlockFiles
   if(!missingDataList.empty()){

      int action;
      
      if (silentlycorrect)
      {
         // In "silently correct" mode, we always create silent blocks. This
         // makes sure the project is complete even if we open it again.
         action = 0;
      } else
      {
         wxString promptA =
            _("Project check detected %d missing audio data blockfile[s] (.au), \nprobably due to a bug, system crash or accidental deletion.\nThere is no way for Audacity to recover this lost data\nautomatically; you may choose to permanently fill in silence\nfor the missing data, temporarily fill in silence for this\nsession only, or close the project now and try to restore the\nmissing data by hand.");
         wxString prompt;
      
         prompt.Printf(promptA,missingDataList.size());
      
         const wxChar *buttons[]={_("Replace missing data with silence [permanent immediately]"),
                                  _("Temporarily replace missing data with silence [this session only]"),
                                 _("Close project immediately with no further changes"),NULL};
         action = ShowMultiDialog(prompt,
                                      _("Warning"),
                                      buttons);
      
         if(action==2)return (ret | FSCKstatus_CLOSEREQ);
      }
      
      BlockHash::iterator i=missingDataList.begin();
      while(i != missingDataList.end()) {
         BlockFile *b = i->second;
         if(action==0){
            //regenerate with zeroes
            b->Recover();
            ret |= FSCKstatus_CHANGED;
         }else if(action==1){
            b->SilenceLog();
         }
         i++;
      }
   }

   // clean up any empty directories
   fnameList.Clear();
   rm_dash_rf_enumerate_prompt((projFull != wxT("")? projFull: mytemp),
                               fnameList,wxEmptyString,0,1,blockcount,
                               _("Cleaning up unused directories in project data..."));
   rm_dash_rf_execute(fnameList,0,0,1,0);


   return ret;
}