Audacity 3.2.0
Enumerations | Functions
ProjectFSCK.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  : unsigned { FSCKstatus_CLOSE_REQ = 0x1 , FSCKstatus_CHANGED = 0x2 , FSCKstatus_SAVE_AUP = 0x4 }
 

Functions

int ProjectFSCK (DirManager &dm, const bool bForceError, const bool bAutoRecoverMode)
 

Enumeration Type Documentation

◆ anonymous enum

anonymous enum : unsigned
Enumerator
FSCKstatus_CLOSE_REQ 
FSCKstatus_CHANGED 
FSCKstatus_SAVE_AUP 

Definition at line 18 of file ProjectFSCK.h.

18 : unsigned {
21 FSCKstatus_SAVE_AUP = 0x4, // used in combination with FSCKstatus_CHANGED
22};
@ FSCKstatus_CHANGED
Definition: ProjectFSCK.h:20
@ FSCKstatus_CLOSE_REQ
Definition: ProjectFSCK.h:19
@ FSCKstatus_SAVE_AUP
Definition: ProjectFSCK.h:21

Function Documentation

◆ ProjectFSCK()

int ProjectFSCK ( DirManager &  dm,
const bool  bForceError,
const bool  bAutoRecoverMode 
)

Definition at line 33 of file ProjectFSCK.cpp.

35{
36#pragma message( "====================================================================")
37#pragma message( "Don\'t forget to redo ProjectFSCK")
38#pragma message( "====================================================================")
39 // In earlier versions of this method, enumerations of errors were
40 // all done in sequence, then the user was prompted for each type of error.
41 // The enumerations are now interleaved with prompting, because, for example,
42 // user choosing to replace missing aliased block files with silence
43 // needs to put in SilentBlockFiles and DELETE the corresponding auf files,
44 // so those would then not be cumulated in missingAUFHash.
45 // We still do the FindX methods outside the conditionals,
46 // so the log always shows all found errors.
47
48 int action; // choice of action for each type of error
49 int nResult = 0;
50
51 if (bForceError && !bAutoRecoverMode)
52 {
53 // TODO: Replace with more user friendly error message?
54 /* i18n-hint: The audacity project file is XML and has 'tags' in it,
55 rather like html tags <something>some stuff</something>.
56 This error message is about the tags that hold the sequence information.
57 The error message is confusing to users in English, and could just say
58 "Found problems with <sequence> when checking project file." */
59 auto msg = XO("Project check read faulty Sequence tags.");
60 const TranslatableStrings buttons{
61 XO("Close project immediately with no changes"),
62 XO("Continue with repairs noted in log, and check for more errors. This will save the project in its current state, unless you \"Close project immediately\" on further error alerts.")
63 };
64 wxLog::FlushActive(); // MultiDialog has "Show Log..." button, so make sure log is current.
65 action = ShowMultiDialog(msg,
66 XO("Warning - Problems Reading Sequence Tags"),
67 buttons,"");
68 if (action == 0)
69 nResult = FSCKstatus_CLOSE_REQ;
70 else
72 }
73#if 0
74 FilePaths filePathArray; // *all* files in the project directory/subdirectories
75 auto dirPath = ( dm.GetDataFilesDir() );
76 DirManager::RecursivelyEnumerateWithProgress(
77 dirPath,
78 filePathArray, // output: all files in project directory tree
79 wxEmptyString, // All dirs
80 wxEmptyString, // All files
81 true, false,
82 dm.NumBlockFiles(), // rough guess of how many BlockFiles will be found/processed, for progress
83 XO("Inspecting project file data"));
84
85 //
86 // MISSING ALIASED AUDIO FILES
87 //
88 MissingAliasFilesDialog::SetShouldShow(false);
89 BlockHash missingAliasFilesAUFHash; // (.auf) AliasBlockFiles whose aliased files are missing
90 BlockHash missingAliasFilesPathHash; // full paths of missing aliased files
91 dm.FindMissingAliasFiles(missingAliasFilesAUFHash, missingAliasFilesPathHash);
92
93 if ((nResult != FSCKstatus_CLOSE_REQ) && !missingAliasFilesAUFHash.empty())
94 {
95 // In auto-recover mode, we always create silent blocks, and do not ask user.
96 // This makes sure the project is complete next time we open it.
97 if (bAutoRecoverMode)
98 action = 2;
99 else
100 {
101 auto msg =
102XO("Project check of \"%s\" folder \
103\ndetected %lld missing external audio file(s) \
104\n('aliased files'). There is no way for Audacity \
105\nto recover these files automatically. \
106\n\nIf you choose the first or second option below, \
107\nyou can try to find and restore the missing files \
108\nto their previous location. \
109\n\nNote that for the second option, the waveform \
110\nmay not show silence. \
111\n\nIf you choose the third option, this will save the \
112\nproject in its current state, unless you \"Close \
113\nproject immediately\" on further error alerts.")
114 .Format(
115 dm.GetProjectName(),
116 (long long) missingAliasFilesPathHash.size() );
117 const TranslatableStrings buttons{
118 XO("Close project immediately with no changes"),
119 XO("Treat missing audio as silence (this session only)"),
120 XO("Replace missing audio with silence (permanent immediately)."),
121 };
122 wxLog::FlushActive(); // MultiDialog has "Show Log..." button, so make sure log is current.
123 action = ShowMultiDialog(msg,
124 XO("Warning - Missing Aliased File(s)"),
125 buttons,
126 "");
127 }
128
129 if (action == 0)
130 nResult = FSCKstatus_CLOSE_REQ;
131 else
132 {
133 // LL: A progress dialog should probably be used here
134 BlockHash::iterator iter = missingAliasFilesAUFHash.begin();
135 while (iter != missingAliasFilesAUFHash.end())
136 {
137 // This type cast is safe. We checked that it's an alias block file earlier.
138 BlockFilePtr b = iter->second.lock();
139 wxASSERT(b);
140 if (b) {
141 auto ab = static_cast< AliasBlockFile * > ( &*b );
142
143 if (action == 2)
144 {
145 // silence the blockfiles by yanking the filename
146 // This is done, eventually, in PCMAliasBlockFile::ReadData(),
147 // in the stack of b->Recover().
148 // There, if the mAliasedFileName is bad, it zeroes the data.
149 wxFileNameWrapper dummy;
150 dummy.Clear();
151 ab->ChangeAliasedFileName(std::move(dummy));
152
153 // If recovery fails for one file, silence it,
154 // and don't try to recover other files but
155 // silence them too. GuardedCall will cause an appropriate
156 // error message for the user.
158 [&] { ab->Recover(); },
159 [&] (AudacityException*) { action = 1; }
160 );
161
163 }
164
165 if (action == 1)
166 // Silence error logging for this block in this session.
167 ab->SilenceAliasLog();
168 }
169 ++iter;
170 }
171 if ((action == 2) && bAutoRecoverMode)
172 wxLogWarning(wxT(" Project check replaced missing aliased file(s) with silence."));
173 }
174 }
175
176 //
177 // MISSING ALIAS (.AUF) AliasBlockFiles
178 //
179 // Alias summary regeneration must happen after checking missing aliased files.
180 //
181 BlockHash missingAUFHash; // missing (.auf) AliasBlockFiles
182 dm.FindMissingAUFs(missingAUFHash);
183 if ((nResult != FSCKstatus_CLOSE_REQ) && !missingAUFHash.empty())
184 {
185 // In auto-recover mode, we just recreate the alias files, and do not ask user.
186 // This makes sure the project is complete next time we open it.
187 if (bAutoRecoverMode)
188 action = 0;
189 else
190 {
191 auto msg =
192XO("Project check of \"%s\" folder \
193\ndetected %lld missing alias (.auf) blockfile(s). \
194\nAudacity can fully regenerate these files \
195\nfrom the current audio in the project.")
196 .Format(
197 dm.GetProjectName(), (long long) missingAUFHash.size() );
198 const TranslatableStrings buttons{
199 XO("Regenerate alias summary files (safe and recommended)"),
200 XO("Fill in silence for missing display data (this session only)"),
201 XO("Close project immediately with no further changes"),
202 };
203 wxLog::FlushActive(); // MultiDialog has "Show Log..." button, so make sure log is current.
204 action = ShowMultiDialog(msg,
205 XO("Warning - Missing Alias Summary File(s)"),
206 buttons,
207 "");
208 }
209
210 if (action == 2)
211 nResult = FSCKstatus_CLOSE_REQ;
212 else
213 {
214 // LL: A progress dialog should probably be used here
215 BlockHash::iterator iter = missingAUFHash.begin();
216 while (iter != missingAUFHash.end())
217 {
218 BlockFilePtr b = iter->second.lock();
219 wxASSERT(b);
220 if (b) {
221 if(action==0) {
222 //regenerate from data
223 // If recovery fails for one file, silence it,
224 // and don't try to recover other files but
225 // silence them too. GuardedCall will cause an appropriate
226 // error message for the user.
228 [&] {
229 b->Recover();
230 nResult |= FSCKstatus_CHANGED;
231 },
232 [&] (AudacityException*) { action = 1; }
233 );
234 }
235
236 if (action==1){
237 // Silence error logging for this block in this session.
238 b->SilenceLog();
239 }
240 }
241 ++iter;
242 }
243 if ((action == 0) && bAutoRecoverMode)
244 wxLogWarning(wxT(" Project check regenerated missing alias summary file(s)."));
245 }
246 }
247
248 //
249 // MISSING (.AU) SimpleBlockFiles
250 //
251 BlockHash missingAUHash; // missing data (.au) blockfiles
252 dm.FindMissingAUs(missingAUHash);
253 if ((nResult != FSCKstatus_CLOSE_REQ) && !missingAUHash.empty())
254 {
255 // In auto-recover mode, we just always create silent blocks.
256 // This makes sure the project is complete next time we open it.
257 if (bAutoRecoverMode)
258 action = 2;
259 else
260 {
261 auto msg =
262XO("Project check of \"%s\" folder \
263\ndetected %lld missing audio data (.au) blockfile(s), \
264\nprobably due to a bug, system crash, or accidental \
265\ndeletion. There is no way for Audacity to recover \
266\nthese missing files automatically. \
267\n\nIf you choose the first or second option below, \
268\nyou can try to find and restore the missing files \
269\nto their previous location. \
270\n\nNote that for the second option, the waveform \
271\nmay not show silence.")
272 .Format(
273 dm.GetProjectName(), (long long) missingAUHash.size() );
274 const TranslatableStrings buttons{
275 XO("Close project immediately with no further changes"),
276 XO("Treat missing audio as silence (this session only)"),
277 XO("Replace missing audio with silence (permanent immediately)"),
278 };
279 wxLog::FlushActive(); // MultiDialog has "Show Log..." button, so make sure log is current.
280 action = ShowMultiDialog(msg,
281 XO("Warning - Missing Audio Data Block File(s)"),
282 buttons,
283 "Warning_-_Missing_Audio_Data_Block_Files");
284 }
285
286 if (action == 0)
287 nResult = FSCKstatus_CLOSE_REQ;
288 else
289 {
290 // LL: A progress dialog should probably be used here
291 BlockHash::iterator iter = missingAUHash.begin();
292 while (iter != missingAUHash.end())
293 {
294 BlockFilePtr b = iter->second.lock();
295 wxASSERT(b);
296 if (b) {
297 if (action == 2)
298 {
299 //regenerate from data
300 // If recovery fails for one file, silence it,
301 // and don't try to recover other files but
302 // silence them too. GuardedCall will cause an appropriate
303 // error message for the user.
305 [&] {
306 //regenerate with zeroes
307 b->Recover();
308 nResult |= FSCKstatus_CHANGED;
309 },
310 [&] (AudacityException*) { action = 1; }
311 );
312 }
313
314 if (action == 1)
315 b->SilenceLog();
316 }
317 ++iter;
318 }
319 if ((action == 2) && bAutoRecoverMode)
320 wxLogWarning(wxT(" Project check replaced missing audio data block file(s) with silence."));
321 }
322 }
323
324 //
325 // ORPHAN BLOCKFILES (.au and .auf files that are not in the project.)
326 //
327 FilePaths orphanFilePathArray; // orphan .au and .auf files
328 dm.FindOrphanBlockFiles(filePathArray, orphanFilePathArray);
329
330 if ((nResult != FSCKstatus_CLOSE_REQ) && !orphanFilePathArray.empty())
331 {
332 // In auto-recover mode, leave orphan blockfiles alone.
333 // They will be deleted when project is saved the first time.
334 if (bAutoRecoverMode)
335 {
336 wxLogWarning(wxT(" Project check ignored orphan block file(s). They will be deleted when project is saved."));
337 action = 1;
338 }
339 else
340 {
341 auto msg =
342XO("Project check of \"%s\" folder \
343\nfound %d orphan block file(s). These files are \
344\nunused by this project, but might belong to \
345other projects. \
346\nThey are doing no harm and are small.")
347 .Format( dm.GetProjectName(), (int)orphanFilePathArray.size() );
348
349 const TranslatableStrings buttons{
350 XO("Continue without deleting; ignore the extra files this session"),
351 XO("Close project immediately with no further changes"),
352 XO("Delete orphan files (permanent immediately)"),
353 };
354 wxLog::FlushActive(); // MultiDialog has "Show Log..." button, so make sure log is current.
355 action = ShowMultiDialog(msg,
356 XO("Warning - Orphan Block File(s)"),
357 buttons,
358 "Warning_-_Orphan_Block_Files"
359 );
360 }
361
362 if (action == 1)
363 nResult = FSCKstatus_CLOSE_REQ;
364 // Nothing is done if (action == 0).
365 else if (action == 2)
366 {
367 // FSCKstatus_CHANGED was bogus here.
368 // The files are deleted, so "Undo Project Repair" could not do anything.
369 // Plus they affect none of the valid tracks, so incorrect to mark them changed,
370 // and no need for refresh.
371 // nResult |= FSCKstatus_CHANGED;
372 for ( const auto &orphan : orphanFilePathArray )
373 wxRemoveFile(orphan);
374 }
375 }
376
377 if (nResult != FSCKstatus_CLOSE_REQ)
378 {
379 // Remove any empty directories.
380 ProgressDialog pProgress(
381 XO("Progress"),
382 XO("Cleaning up unused directories in project data"));
383 // nDirCount is for updating pProgress. +1 because we may DELETE dirPath.
384 int nDirCount = DirManager::RecursivelyCountSubdirs(dirPath) + 1;
385 DirManager::RecursivelyRemoveEmptyDirs(dirPath, nDirCount, &pProgress);
386 }
387
388 // Summarize and flush the log.
389 if (bForceError ||
390 !missingAliasFilesAUFHash.empty() ||
391 !missingAUFHash.empty() ||
392 !missingAUHash.empty() ||
393 !orphanFilePathArray.empty())
394 {
395 wxLogWarning(wxT("Project check found file inconsistencies inspecting the loaded project data."));
396 wxLog::FlushActive(); // Flush is modal and will clear the log (both desired).
397
398 // In auto-recover mode, we didn't do any ShowMultiDialog calls above, so put up an alert.
399 if (bAutoRecoverMode)
401 XO(
402"Project check found file inconsistencies during automatic recovery.\n\nSelect 'Help > Diagnostics > Show Log...' to see details."),
403 XO("Warning: Problems in Automatic Recovery"),
404 wxOK | wxICON_EXCLAMATION);
405 }
406
407 MissingAliasFilesDialog::SetShouldShow(true);
408#endif
409 return nResult;
410}
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
#define XO(s)
Definition: Internat.h:31
int ShowMultiDialog(const TranslatableString &message, const TranslatableString &title, const TranslatableStrings &buttons, const ManualPageID &helpPage, const TranslatableString &boxMsg, bool log)
std::vector< TranslatableString > TranslatableStrings
Base class for exceptions specially processed by the application.
ProgressDialog Class.
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.

References AudacityMessageBox(), FSCKstatus_CHANGED, FSCKstatus_CLOSE_REQ, FSCKstatus_SAVE_AUP, GuardedCall(), ShowMultiDialog(), and XO.

Here is the call graph for this function: