private void refreshFolders(boolean recursive, TaskMonitor monitor) throws IOException {

		String path = getPathname();
		HashSet<String> newSet = new HashSet<>();

		if (folderExists) {
			try {
				String[] folders = fileSystem.getFolderNames(path);
				newSet.addAll(Arrays.asList(folders));
			}
			catch (IOException e) {
				if (parent != null) {
					parent.folderRemoved(name);
				}
				throw e;
			}
		}
		if (versionedFolderExists) {
			try {
				String[] folders = versionedFileSystem.getFolderNames(path);
				newSet.addAll(Arrays.asList(folders));
			}
			catch (Exception e) {
				Msg.error(this, "versioned folder refresh failed: " + e.getMessage());
				versionedFolderExists = false;
			}
		}

		HashSet<String> oldSet = new HashSet<>();
		for (String folder : folderList) {
			oldSet.add(folder);
		}
		HashSet<String> oldSetClone = new HashSet<>(oldSet);
		// find deleted folders
		oldSet.removeAll(newSet);
		for (String folderName : oldSet) {
			GhidraFolderData folderData = folderDataCache.remove(folderName);
			if (folderData != null) {
				folderData.dispose();
			}
			folderList.remove(folderName);
			if (visited) {
				listener.domainFolderRemoved(getDomainFolder(), folderName);
			}
		}

		// Recurse through pre-existing folders
		if (recursive) {
			for (String folderName : folderList) {
				if (monitor != null && monitor.isCancelled()) {
					break; // break-out from recursion on cancel
				}
				GhidraFolderData folderData = folderDataCache.get(folderName);
				if (folderData != null && folderData.visited) {
					folderData.refresh(true, true, monitor);
				}
			}
		}

		// find new folders
		newSet.removeAll(oldSetClone);
		for (String folderName : newSet) {
			GhidraFolderData folderData = addFolderData(folderName);
			if (folderData != null) {
				folderList.add(folderName);
				if (visited) {
					listener.domainFolderAdded(folderData.getDomainFolder());
				}
			}
		}
	}
Refresh set of sub-folder names and identify added/removed folders.
@param recursive recurse into visited subfolders if true
@param monitor recursion task monitor - break from recursion if cancelled
@throws IOException if an IO error occurs during the refresh
Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFolderData.java