private SymbolFileLocation copyRemoteToLocal(SymbolFileLocation symbolFileLocation,
			TaskMonitor monitor) throws CancelledException, IOException {
		int tryCount = 0;
		while (true) {
			Msg.debug(this,
				"%s try[%d]: copying file %s from remote to local %s".formatted(logPrefix(),
					tryCount, symbolFileLocation.getLocationStr(), symbolStore.getName()));

			// copy from remote store to our main local symbol store
			String remoteFilename = FilenameUtils.getName(symbolFileLocation.getPath());
			try (SymbolServerInputStream symbolServerInputStream =
				symbolFileLocation.getSymbolServer()
						.getFileStream(symbolFileLocation.getPath(), monitor)) {
				String newPath = symbolStore.putStream(symbolFileLocation.getFileInfo(),
					symbolServerInputStream, remoteFilename, monitor);
				return new SymbolFileLocation(newPath, symbolStore,
					symbolFileLocation.getFileInfo());
			}
			catch (IOException e) {
				String msg = "%s: error copying file %s to %s: %s".formatted(logPrefix(),
					symbolFileLocation.getLocationStr(), symbolStore.getName(), e.getMessage());
				if (++tryCount >= MAX_TRY_COUNT) {
					Msg.error(this, msg);
					throw e; // failure
				}

				// allow retry
				Msg.warn(this, msg);
			}
		}
	}
Converts a possibly remote {@link SymbolFileLocation} to a location that is local and
uncompressed.

@param symbolFileLocation possibly remote {@link SymbolFileLocation}
@param monitor {@link TaskMonitor} to display progress and allow canceling
@return {@link SymbolFileLocation} that is local (possibly the same  instance if already
local)
@throws CancelledException if canceled
@throws IOException if error
Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolServerService.java