Skip to content

feat: support search in network locations via GIO - #2032

Open
BlakeGardner wants to merge 2 commits into
pop-os:masterfrom
BlakeGardner:feat/network-search
Open

feat: support search in network locations via GIO#2032
BlakeGardner wants to merge 2 commits into
pop-os:masterfrom
BlakeGardner:feat/network-search

Conversation

@BlakeGardner

@BlakeGardner BlakeGardner commented Aug 31, 2026

Copy link
Copy Markdown
  • I have disclosed use of any AI generated code in my commit messages.
  • I understand these changes in full and will be able to respond to review comments.
  • My change is accurately described in the commit message.
  • My contribution is tested and working as described.
  • I have read the Developer Certificate of Origin and certify my contribution under its conditions.

Problem

Network share search is broken in two ways:

  1. It silently does nothing on locations without a gvfs-fuse path, such as
    shares opened from the Networks page or a URI typed into the location
    bar. No SearchLocation can be derived, so keystrokes are dropped.
  2. On mounted shares it is extremely slow and freezes the UI. The walk pays
    per-entry round trips through the FUSE layer, and each keystroke also
    runs synchronous fuse I/O on the UI thread (change_location calls
    Location::normalize), which stalls behind the walker and locks up
    the app.

Solution

Add SearchLocation::Network and a gvfs network_search that recursively
enumerates the location URI with GIO, the same approach scan_path already
uses for gvfs mounts (see #1996). Entries arrive in batches with metadata
instead of per-entry fuse round trips, which makes search on network shares
massively faster (see videos). The search location carries no local path,
so no fuse I/O runs on the UI thread and the freezes are gone. Works with
any GVFS backend, does not require gvfs-fuse, and clearing the search
returns to the network view instead of the raw gvfs path. The network:///
browse tree stays excluded since its entries may not be mounted.

Demos

New: type-to-search on a share opened via the Networks page (~1,700 movie
folders). Plus massive speed increase.

type_to_search.mp4

Old fuse-path search on the same share, mounted. Slow, with UI freezes:

slow-search.mp4

Testing Notes

  • Manually tested on SMB: a real NAS with ~1,700 movie folders, plus a
    local samba container with emulated latency
  • 4 unit tests cover the GIO traversal using file:// URIs: recursion,
    hidden files, early cancellation, result locations, symlink cycles

See below for reproducible way to set up network share with lots of files and artificially induced lag to test speedup.

QA: reproducible test environment (fake SMB movie share)

Generate a fake movie library and serve it over SMB with guest access
(sparse files, ~200K real disk usage), then add LAN NAS latency
(2 ms with 0.5 ms jitter, 300 mbit) so loopback speed does not mask
the behavior being tested:

mkdir -p /tmp/qa-movies && cd /tmp/qa-movies
for i in $(seq -w 1 300); do
  d="Movie $i ($((1950+10#$i%75)))"; mkdir -p "$d/Subs"
  truncate -s 100M "$d/movie-$i.mkv"
  echo sub > "$d/movie-$i.en.srt"
  echo sub > "$d/Subs/movie-$i.forced.srt"
done
mkdir "The Needle Protocol (1999)"
truncate -s 1G "The Needle Protocol (1999)/needle.mkv"
touch "The Needle Protocol (1999)/.needle-hidden.srt"

docker run --rm -d --name qa-smb -p 445:445 -v /tmp/qa-movies:/movies:ro \
  dperson/samba -s "movies;/movies;yes;yes;yes"

docker run --rm --net container:qa-smb --cap-add NET_ADMIN alpine \
  sh -c 'apk add -q iproute2-tc && tc qdisc replace dev eth0 root netem delay 2ms 500us distribution normal rate 300mbit'

Test steps:

  1. Press Ctrl+L, enter smb://localhost/movies, connect as guest.
    Entering a URI this way is the case that was broken (network location
    with no fuse path).
  2. Type needle: search opens and finds the folder and needle.mkv.
    On master this does nothing.
  3. Ctrl+H: .needle-hidden.srt appears as a third result.
  4. Type forced: 300 results stream in from nested Subs folders.
  5. Esc: returns to the share view, not a /run/user/*/gvfs path.
  6. Compare with the share opened from its mounted sidebar entry on
    master to see the fuse-path slowness and freezes.

Cleanup: docker rm -f qa-smb && rm -rf /tmp/qa-movies

@chris-010

Copy link
Copy Markdown
Contributor

Two things from the same corner, both from reading the diff — I have not run this branch.

Shares in a server listing look like they will be skipped. network_search() queues a child only when info.file_type() is Directory, and gvfs reports a share below smb://server/ as Mountable (measured here against 1.5.0 while working on #1972), so the traversal would stop at the server root. The child it would descend into, dir.child(info.name()), is the backend-internal smb://server/._share as well; what resolves that is standard::target-uri, which the SCAN_ATTRIBUTES list you reuse does not request — #1996 has the same note.

Overlap, unrelated to the above: the app.rs and dialog.rs hunks sit on search_set, which #1966 rewrites in both copies. Whichever lands first, the other needs a rebase there.

@BlakeGardner

BlakeGardner commented Sep 3, 2026

Copy link
Copy Markdown
Author

Two things from the same corner, both from reading the diff — I have not run this branch.

Shares in a server listing look like they will be skipped. network_search() queues a child only when info.file_type() is Directory, and gvfs reports a share below smb://server/ as Mountable (measured here against 1.5.0 while working on #1972), so the traversal would stop at the server root. The child it would descend into, dir.child(info.name()), is the backend-internal smb://server/._share as well; what resolves that is standard::target-uri, which the SCAN_ATTRIBUTES list you reuse does not request — #1996 has the same note.

Overlap, unrelated to the above: the app.rs and dialog.rs hunks sit on search_set, which #1966 rewrites in both copies. Whichever lands first, the other needs a rebase there.

Good catch, you were right on both. Fixed in 881c8fd -- search now requests target-uri and descends into mountable entries. Typing to search on a server view now works, assuming the share(s) are mounted. Unmounted shares are silently skipped, so no mount prompts.

And yeah, happy to rebase my search_set changes if #1966 lands first.

Searching (including type-to-search) previously did nothing when
browsing a network location without a gvfs-fuse path, such as shares
opened through the Networks page or a URI typed into the location bar,
because no SearchLocation could be derived for them.

Add SearchLocation::Network and a gvfs mounter backend that searches
recursively over the location URI with GIO enumerate_children, the
same approach scan_path already uses for listing gvfs mounts. This
works without gvfs-fuse, is faster than walking the fuse path since
entries arrive in batches without per-file stat round trips, and
returns to the network view when the search is cleared.

The network:/// browse tree is excluded since its entries are servers
that may not be mounted.

This change was developed with AI assistance. I have reviewed and
tested the changes and understand them in full.
Shares below a server URI such as smb://server/ are reported by gvfs
as mountable entries, not directories, and their canonical location is
only available in the standard::target-uri attribute. The search
traversal only queued directories, so a search started from a server
view matched share names without descending into any share.

Request target-uri during search enumeration and queue mountable
entries via their resolved URI. Mounted shares are now searched
recursively; enumerating an unmounted share fails with NotMounted and
is skipped, so no mount prompts are triggered. Also track visited URIs
to guard against traversal cycles now that redirects are followed.

Verified against a samba container: gio reports the share as mountable
with a target-uri, search from the server view now recurses into the
mounted share, and completes cleanly with only the share name match
when the share is unmounted.

This change was developed with AI assistance. I have reviewed and
tested the changes and understand them in full.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants