@@ -106,7 +106,11 @@ PluginProcessor::PluginProcessor()
106106 // Initialise directory structure and settings file, do this only once if we're inside the DAW
107107 static bool filesystemInitialised = false ;
108108 if (!filesystemInitialised) {
109- initialiseFilesystem ();
109+ auto succeeded = initialiseFilesystem ();
110+ if (!succeeded)
111+ {
112+ logError (" Failed to initialise filesystem. Is the disk full?" );
113+ }
110114 filesystemInitialised = true ;
111115 }
112116 settingsFile = SettingsFile::getInstance ()->initialise ();
@@ -219,7 +223,7 @@ void PluginProcessor::doubleFlushMessageQueue()
219223 unlockAudioThread ();
220224}
221225
222- void PluginProcessor::initialiseFilesystem ()
226+ bool PluginProcessor::initialiseFilesystem ()
223227{
224228 auto const & homeDir = ProjectInfo::appDataDir;
225229 auto const & versionDataDir = ProjectInfo::versionDataDir;
@@ -249,9 +253,11 @@ void PluginProcessor::initialiseFilesystem()
249253
250254 initMutex.create ();
251255
256+ bool extractionCompleted = true ;
257+
252258 // Check if the abstractions directory exists, if not, unzip it from binaryData
253259 if (!versionDataDir.exists ()) {
254-
260+ extractionCompleted = false ;
255261 // Binary data shouldn't be too big, then the compiler will run out of memory
256262 // To prevent this, we split the binarydata into multiple files, and add them back together here
257263 HeapArray<uint8_t > allData;
@@ -269,13 +275,30 @@ void PluginProcessor::initialiseFilesystem()
269275 }
270276
271277 versionDataDir.getParentDirectory ().createDirectory ();
272- auto const tempVersionDataDir = versionDataDir.getParentDirectory ().getChildFile (" plugdata_version" );
273-
274- versionDataDir.getParentDirectory ().createDirectory ();
275- Decompress::extractTarXz (allData.data (), allData.size (), tempVersionDataDir.getParentDirectory (), 40 * 1024 * 1024 );
278+ int maxRetries = 3 ;
279+ int retryCount = 0 ;
276280
277- // Create filesystem for this specific version
278- tempVersionDataDir.moveFileTo (versionDataDir);
281+ while (!extractionCompleted && retryCount < maxRetries) {
282+ auto const tempVersionDataDir = versionDataDir.getParentDirectory ().getChildFile (" plugdata_version" );
283+
284+ tempVersionDataDir.deleteRecursively ();
285+
286+ if (!versionDataDir.getParentDirectory ().createDirectory ()) {
287+ retryCount++;
288+ continue ;
289+ }
290+
291+ if (!Decompress::extractTarXz (allData.data (), allData.size (), tempVersionDataDir.getParentDirectory (), 40 * 1024 * 1024 )) {
292+ retryCount++;
293+ continue ;
294+ }
295+
296+ extractionCompleted = tempVersionDataDir.moveFileTo (versionDataDir);
297+ if (!extractionCompleted) {
298+ retryCount++;
299+ Thread::sleep (100 );
300+ }
301+ }
279302 }
280303 if (!dekenDir.exists ()) {
281304 dekenDir.createDirectory ();
@@ -296,12 +319,27 @@ void PluginProcessor::initialiseFilesystem()
296319
297320 File (versionDataDir.getChildFile (" ./Documentation/7.stuff/tools/testtone.pd" )).copyFileTo (testTonePatch);
298321 File (versionDataDir.getChildFile (" ./Documentation/7.stuff/tools/load-meter.pd" )).copyFileTo (cpuTestPatch);
299-
300- // We want to recreate these symlinks so that they link to the abstractions/docs for the current plugdata version
301- homeDir.getChildFile (" Abstractions" ).deleteFile ();
302- homeDir.getChildFile (" Documentation" ).deleteFile ();
303- homeDir.getChildFile (" Extra" ).deleteFile ();
304-
322+
323+ auto createLinkWithRetry = [&extractionCompleted](const File& linkPath, const File& targetPath, int maxRetries = 3 ) {
324+ for (int retry = 0 ; retry < maxRetries; retry++) {
325+ #if JUCE_WINDOWS
326+ // Clean up existing link/directory
327+ if (linkPath.exists ()) {
328+ linkPath.deleteRecursively ();
329+ }
330+
331+ if (OSUtils::createJunction (linkPath.getFullPathName ().replaceCharacters (" /" , " \\ " ).toStdString (), targetPath.getFullPathName ().toStdString ())) return ;
332+ #else
333+ if (targetPath.createSymbolicLink (linkPath, true )) return ;
334+ #endif
335+
336+ if (retry < maxRetries - 1 ) {
337+ Thread::sleep (100 );
338+ }
339+ }
340+ extractionCompleted = false ;
341+ };
342+
305343 // We always want to update the symlinks in case an older version of plugdata was used
306344#if JUCE_WINDOWS
307345 // Get paths that need symlinks
@@ -310,11 +348,10 @@ void PluginProcessor::initialiseFilesystem()
310348 auto extraPath = versionDataDir.getChildFile (" Extra" ).getFullPathName ().replaceCharacters (" /" , " \\ " );
311349 auto dekenPath = dekenDir.getFullPathName ();
312350 auto patchesPath = patchesDir.getFullPathName ();
313-
314- // Create NTFS directory junctions
315- OSUtils::createJunction (homeDir.getChildFile (" Abstractions" ).getFullPathName ().replaceCharacters (" /" , " \\ " ).toStdString (), abstractionsPath.toStdString ());
316- OSUtils::createJunction (homeDir.getChildFile (" Documentation" ).getFullPathName ().replaceCharacters (" /" , " \\ " ).toStdString (), documentationPath.toStdString ());
317- OSUtils::createJunction (homeDir.getChildFile (" Extra" ).getFullPathName ().replaceCharacters (" /" , " \\ " ).toStdString (), extraPath.toStdString ());
351+
352+ createLinkWithRetry (homeDir.getChildFile (" Abstractions" ), versionDataDir.getChildFile (" Abstractions" ));
353+ createLinkWithRetry (homeDir.getChildFile (" Documentation" ), versionDataDir.getChildFile (" Documentation" ));
354+ createLinkWithRetry (homeDir.getChildFile (" Extra" ), versionDataDir.getChildFile (" Extra" ));
318355
319356 auto oldlocation = File::getSpecialLocation (File::SpecialLocationType::userDocumentsDirectory).getChildFile (" plugdata" );
320357 auto backupLocation = File::getSpecialLocation (File::SpecialLocationType::userDocumentsDirectory).getChildFile (" plugdata.old" );
@@ -330,9 +367,9 @@ void PluginProcessor::initialiseFilesystem()
330367 auto shortcut = File::getSpecialLocation (File::SpecialLocationType::userDocumentsDirectory).getChildFile (" plugdata.LNK" );
331368 ProjectInfo::appDataDir.createShortcut (" plugdata" , shortcut);
332369#elif JUCE_IOS
333- versionDataDir .getChildFile (" Abstractions" ). createSymbolicLink (homeDir. getChildFile (" Abstractions" ), true );
334- versionDataDir .getChildFile (" Documentation" ). createSymbolicLink (homeDir. getChildFile (" Documentation" ), true );
335- versionDataDir .getChildFile (" Extra" ). createSymbolicLink (homeDir. getChildFile (" Extra" ), true );
370+ createLinkWithRetry (homeDir .getChildFile (" Abstractions" ), versionDataDir. getChildFile (" Abstractions" ));
371+ createLinkWithRetry (homeDir .getChildFile (" Documentation" ), versionDataDir. getChildFile (" Documentation" ));
372+ createLinkWithRetry (homeDir .getChildFile (" Extra" ), versionDataDir. getChildFile (" Extra" ));
336373
337374 auto docsPatchesDir = File::getSpecialLocation (File::SpecialLocationType::userDocumentsDirectory).getChildFile (" Patches" );
338375 docsPatchesDir.createDirectory ();
@@ -343,12 +380,13 @@ void PluginProcessor::initialiseFilesystem()
343380 }
344381 docsPatchesDir.createSymbolicLink (patchesDir, true );
345382#else
346- versionDataDir .getChildFile (" Abstractions" ). createSymbolicLink (homeDir. getChildFile (" Abstractions" ), true );
347- versionDataDir .getChildFile (" Documentation" ). createSymbolicLink (homeDir. getChildFile (" Documentation" ), true );
348- versionDataDir .getChildFile (" Extra" ). createSymbolicLink (homeDir. getChildFile (" Extra" ), true );
383+ createLinkWithRetry (homeDir .getChildFile (" Abstractions" ), versionDataDir. getChildFile (" Abstractions" ));
384+ createLinkWithRetry (homeDir .getChildFile (" Documentation" ), versionDataDir. getChildFile (" Documentation" ));
385+ createLinkWithRetry (homeDir .getChildFile (" Extra" ), versionDataDir. getChildFile (" Extra" ));
349386#endif
350387
351388 initMutex.deleteFile ();
389+ return extractionCompleted;
352390}
353391
354392void PluginProcessor::updateSearchPaths ()
0 commit comments