public static void removeObsoleteGeocacheDataDirectories() {
        withAccessLock(() -> {

            // force-remove caches marked as "to be deleted", ignoring 72h grace period
            try {
                final Set<String> geocodes = new HashSet<>();
                queryToColl(dbTableCaches,
                        new String[]{"geocode"},
                        "geocode NOT IN (SELECT DISTINCT (geocode) FROM " + dbTableCachesLists + ")",
                        null,
                        null,
                        null,
                        geocodes,
                        GET_STRING_0);
                final Set<String> withoutOfflineLogs = exceptCachesWithOfflineLog(geocodes);
                Log.d("forced database clean: removing " + withoutOfflineLogs.size() + " geocaches ignoring grace period");
                removeCaches(withoutOfflineLogs, LoadFlags.REMOVE_ALL);

                deleteOrphanedRecords();
            } catch (final Exception e) {
                Log.w("DataStore.clean", e);
            }

            // remove orphaned files/folders
            final File[] files = LocalStorage.getGeocacheDataDirectory().listFiles();
            if (ArrayUtils.isNotEmpty(files)) {
                final SQLiteStatement select = PreparedStatement.CHECK_IF_PRESENT.getStatement();
                final List<File> toRemove = new ArrayList<>(files.length);
                for (final File file : files) {
                    if (file.isDirectory()) {
                        final String geocode = file.getName();
                        if (!HtmlImage.SHARED.equals(geocode)) {
                            synchronized (select) {
                                select.bindString(1, geocode);
                                if (select.simpleQueryForLong() == 0) {
                                    toRemove.add(file);
                                }
                            }
                        }
                    }
                }

                // Use a background thread for the real removal to avoid keeping the database locked
                // if we are called from within a transaction.
                Schedulers.io().scheduleDirect(() -> {
                    for (final File dir : toRemove) {
                        Log.i("Removing obsolete cache directory for " + dir.getName());
                        FileUtils.deleteDirectory(dir);
                    }
                });
            }

            reindexDatabase();
        });
    }
Remove obsolete cache directories in c:geo private storage.
Also removes caches marked as "to be deleted" immediately (ignoring 72h grace period!)
main/src/main/java/cgeo/geocaching/storage/DataStore.java