@@ -3,7 +3,7 @@ module main;
33
44// What does this module require to function?
55import core.memory ;
6- import core.stdc.errno : ENOENT , EINTR , EBUSY , EXDEV , EAGAIN , EPERM , EACCES , EROFS ;
6+ import core.stdc.errno : EINTR , EBUSY , EXDEV , EAGAIN , EPERM , EACCES , EROFS ;
77import core.stdc.stdlib : EXIT_SUCCESS , EXIT_FAILURE , exit;
88import core.sys.posix.signal ;
99import core.sys.posix.unistd : write, _exit, STDERR_FILENO ;
@@ -1217,7 +1217,7 @@ int main(string[] cliArgs) {
12171217 // If we are in a --download-only method of operation, there is no filesystem monitoring, so no inotify events to check
12181218 if (! appConfig.getValueBool(" download_only" )) {
12191219 // Process any inotify events queued before this loop iteration
1220- processInotifyEvents(true );
1220+ processInotifyEvents();
12211221 }
12221222
12231223 // WebSocket and Webhook Notification Handling
@@ -1358,10 +1358,10 @@ int main(string[] cliArgs) {
13581358 performStandardSyncProcess(localPath, filesystemMonitor);
13591359 }
13601360
1361- // Handle any local filesystem events that occurred while the sync was running.
1362- // Remote-generated and genuine concurrent local events are both processed at
1363- // each reconciliation boundary; database/hash checks suppress harmless echoes .
1364- processInotifyEvents(true );
1361+ // Handle every local filesystem event queued while the sync was running.
1362+ // Event-origin and reconciliation safeguards are handled by the sync engine;
1363+ // the monitor layer must not consume queued events selectively .
1364+ processInotifyEvents();
13651365
13661366 // Detail the outcome of the sync process
13671367 displaySyncOutcome();
@@ -1661,7 +1661,7 @@ void oneDriveOnlineCallback() {
16611661 // If we are in a --download-only method of operation, there is no filesystem monitoring, so no inotify events to check
16621662 if (! appConfig.getValueBool(" download_only" )) {
16631663 // Handle inotify events queued before online reconciliation
1664- processInotifyEvents(true );
1664+ processInotifyEvents();
16651665 }
16661666
16671667 // Sync any online change down to the local disk.
@@ -1673,19 +1673,17 @@ void oneDriveOnlineCallback() {
16731673 appConfig.monitorSyncTriggeredByApiSignal = false ;
16741674 }
16751675
1676- syncEngineInstance.syncOneDriveAccountToLocalDisk();
1676+ syncEngineInstance.syncOneDriveAccountToLocalDisk(delegate () { processInotifyEvents(); } );
16771677
16781678 if (syncEngineInstance.authoritativeCleanupPassUsedInLastSync) {
16791679 syncEngineInstance.performDatabaseConsistencyAndIntegrityCheck();
16801680 }
16811681 }
16821682 if (appConfig.getValueBool(" monitor" )) {
16831683 // Process every queued inotify event after online -> local reconciliation.
1684- // The database and local filesystem have already been updated by the remote
1685- // reconciliation, so self-generated events are naturally filtered by the
1686- // existing database/hash checks. Genuine concurrent local events must not be
1687- // consumed and discarded here.
1688- processInotifyEvents(true );
1684+ // Online-originated events still require explicit origin and deletion-precedence
1685+ // handling; the monitor layer must not discard events based on presumed origin.
1686+ processInotifyEvents();
16891687 }
16901688}
16911689
@@ -1695,14 +1693,14 @@ void performUploadOnlySyncProcess(string localPath, Monitor filesystemMonitor =
16951693 syncEngineInstance.performDatabaseConsistencyAndIntegrityCheck();
16961694 if (appConfig.getValueBool(" monitor" )) {
16971695 // Handle any inotify events whilst the DB was being scanned
1698- processInotifyEvents(true );
1696+ processInotifyEvents();
16991697 }
17001698
17011699 // Scan the configured 'sync_dir' for new data to upload
17021700 syncEngineInstance.scanLocalFilesystemPathForNewData(localPath);
17031701 if (appConfig.getValueBool(" monitor" )) {
17041702 // Handle any new inotify events whilst the local filesystem was being scanned
1705- processInotifyEvents(true );
1703+ processInotifyEvents();
17061704 }
17071705}
17081706
@@ -1726,23 +1724,23 @@ void performStandardSyncProcess(string localPath, Monitor filesystemMonitor = nu
17261724 syncEngineInstance.performDatabaseConsistencyAndIntegrityCheck();
17271725 if (appConfig.getValueBool(" monitor" )) {
17281726 // Handle any inotify events whilst the DB was being scanned
1729- processInotifyEvents(true );
1727+ processInotifyEvents();
17301728 }
17311729
17321730 // Scan the configured 'sync_dir' for new data to upload to OneDrive
17331731 syncEngineInstance.scanLocalFilesystemPathForNewData(localPath);
17341732 if (appConfig.getValueBool(" monitor" )) {
17351733 // Handle any new inotify events whilst the local filesystem was being scanned
1736- processInotifyEvents(true );
1734+ processInotifyEvents();
17371735 }
17381736
17391737 // Download data from OneDrive last
1740- syncEngineInstance.syncOneDriveAccountToLocalDisk();
1738+ syncEngineInstance.syncOneDriveAccountToLocalDisk(delegate () { processInotifyEvents(); } );
17411739 if (appConfig.getValueBool(" monitor" )) {
1742- // Process all queued inotify events. Events caused by the completed remote
1743- // reconciliation are filtered by current database/hash state; concurrent
1744- // local activity must remain actionable .
1745- processInotifyEvents(true );
1740+ // Process all queued inotify events. Concurrent local activity must remain
1741+ // actionable; online-originated events are handled by the active-pass
1742+ // deletion-precedence protection where applicable .
1743+ processInotifyEvents();
17461744 }
17471745
17481746 // At this point, we have done a sync from:
@@ -1758,19 +1756,19 @@ void performStandardSyncProcess(string localPath, Monitor filesystemMonitor = nu
17581756 } else {
17591757 // Normal sync process
17601758 // Download data from OneDrive first
1761- syncEngineInstance.syncOneDriveAccountToLocalDisk();
1759+ syncEngineInstance.syncOneDriveAccountToLocalDisk(delegate () { processInotifyEvents(); } );
17621760 if (appConfig.getValueBool(" monitor" )) {
1763- // Process all queued inotify events. Events caused by the completed remote
1764- // reconciliation are filtered by current database/hash state; concurrent
1765- // local activity must remain actionable .
1766- processInotifyEvents(true );
1761+ // Process all queued inotify events. Concurrent local activity must remain
1762+ // actionable; online-originated events are handled by the active-pass
1763+ // deletion-precedence protection where applicable .
1764+ processInotifyEvents();
17671765 }
17681766
17691767 // Perform the local database consistency check, picking up locally modified data and uploading this to OneDrive
17701768 syncEngineInstance.performDatabaseConsistencyAndIntegrityCheck();
17711769 if (appConfig.getValueBool(" monitor" )) {
17721770 // Handle any inotify events whilst the DB was being scanned
1773- processInotifyEvents(true );
1771+ processInotifyEvents();
17741772 }
17751773
17761774 // Is --download-only NOT configured?
@@ -1780,7 +1778,7 @@ void performStandardSyncProcess(string localPath, Monitor filesystemMonitor = nu
17801778 syncEngineInstance.scanLocalFilesystemPathForNewData(localPath);
17811779 if (appConfig.getValueBool(" monitor" )) {
17821780 // Handle any new inotify events whilst the local filesystem was being scanned
1783- processInotifyEvents(true );
1781+ processInotifyEvents();
17841782 }
17851783
17861784 // If we are not doing a 'force_children_scan' perform a true-up
@@ -1794,12 +1792,11 @@ void performStandardSyncProcess(string localPath, Monitor filesystemMonitor = nu
17941792 }
17951793 // We pass in the 'appConfig.fullScanTrueUpRequired' value which then flags do we use the configured 'deltaLink'
17961794 // If 'appConfig.fullScanTrueUpRequired' is true, we do not use the 'deltaLink' if we are in --monitor mode, thus forcing a full scan true up
1797- syncEngineInstance.syncOneDriveAccountToLocalDisk();
1795+ syncEngineInstance.syncOneDriveAccountToLocalDisk(delegate () { processInotifyEvents(); } );
17981796 if (appConfig.getValueBool(" monitor" )) {
1799- // Process all queued inotify events after the final online true-up.
1800- // Never consume concurrent local changes merely because remote work
1801- // also generated filesystem notifications.
1802- processInotifyEvents(true );
1797+ // Process every queued inotify event after the final online true-up.
1798+ // Event-origin and reconciliation safeguards are handled by the sync engine.
1799+ processInotifyEvents();
18031800 }
18041801 } else {
18051802 // exitHandlerTriggered triggered
@@ -1823,34 +1820,22 @@ void performStandardSyncProcess(string localPath, Monitor filesystemMonitor = nu
18231820 }
18241821}
18251822
1826- // Process any inotify events
1827- void processInotifyEvents (bool updateFlag, bool processDeletesWhenDraining = false ) {
1823+ // Process and dispatch every queued inotify event. There is intentionally no
1824+ // cancellation or selective-drain mode because consuming an event without
1825+ // dispatching it can lose genuine local activity.
1826+ void processInotifyEvents () {
18281827 if ((filesystemMonitor is null ) || (! filesystemMonitor.initialised)) {
18291828 return ;
18301829 }
18311830
1832- // Attempt to process or cancel inotify events
1833- // filesystemMonitor.update will throw this, thus needs to be caught
1834- // monitor.MonitorException@src/monitor.d(549): inotify queue overflow: some events may be lost (Interrupted system call)
18351831 try {
1836- // Process any inotify events or cancel events based on flag value
1837- // True = process
1838- // False = cancel
1839- filesystemMonitor.update(updateFlag, processDeletesWhenDraining);
1832+ filesystemMonitor.update();
18401833 } catch (MonitorException exception) {
18411834 // Catch any exceptions thrown by inotify / monitor engine
18421835 addLogEntry(" ERROR: The following inotify error was generated: " ~ exception.msg);
18431836 } catch (FileException exception) {
1844- // A local path can legitimately disappear while queued inotify events are
1845- // being cancelled / drained, especially under monitor stress testing.
1846- // Treat ENOENT during event cancellation as non-fatal.
1847- if ((! updateFlag) && (exception.errno == ENOENT )) {
1848- if (debugLogging) {
1849- addLogEntry(" Ignoring stale inotify cancellation event for path that no longer exists: " ~ exception.msg, [" debug" ]);
1850- }
1851- return ;
1852- }
1853- // Log error message
1837+ // Preserve the existing full-processing behaviour: filesystem errors are
1838+ // reported rather than silently converting them into discarded events.
18541839 addLogEntry(" ERROR: The following filesystem error was generated while processing inotify events: " ~ exception.msg);
18551840 }
18561841}
0 commit comments