Skip to content

Commit 881c8fd

Browse files
committed
fix: descend into mountable share entries during network search
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.
1 parent d70fb7b commit 881c8fd

1 file changed

Lines changed: 23 additions & 3 deletions

File tree

src/mounter/gvfs.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,12 +279,22 @@ fn network_search(
279279
) -> Result<(), String> {
280280
let (_, root) = resolve_uri(uri);
281281

282+
// Shares in a server listing are mountable entries whose canonical
283+
// location is only available in the target-uri attribute
284+
let attributes = format!("{SCAN_ATTRIBUTES},{TARGET_URI_ATTRIBUTE}");
285+
282286
// Breadth-first traversal of the network location
283287
let mut first = true;
288+
let mut visited = std::collections::HashSet::new();
284289
let mut queue = std::collections::VecDeque::from([root]);
285290
while let Some(dir) = queue.pop_front() {
291+
// Guard against traversal cycles introduced by target-uri redirects
292+
if !visited.insert(String::from(dir.uri())) {
293+
continue;
294+
}
295+
286296
let enumerator = match dir.enumerate_children(
287-
SCAN_ATTRIBUTES,
297+
&attributes,
288298
// Do not follow symlinks to avoid traversal cycles
289299
gio::FileQueryInfoFlags::NOFOLLOW_SYMLINKS,
290300
gio::Cancellable::NONE,
@@ -322,8 +332,18 @@ fn network_search(
322332
}
323333
}
324334

325-
if matches!(info.file_type(), gio::FileType::Directory) {
326-
queue.push_back(dir.child(info.name()));
335+
match info.file_type() {
336+
gio::FileType::Directory => queue.push_back(dir.child(info.name())),
337+
// Shares below a server (e.g. smb://server/) are mountable
338+
// entries; descend into them via their resolved location.
339+
// Enumerating an unmounted share fails with NotMounted and
340+
// is skipped above, so this never triggers mount prompts
341+
gio::FileType::Mountable => {
342+
if let Some(target_uri) = info.attribute_as_string(TARGET_URI_ATTRIBUTE) {
343+
queue.push_back(gio::File::for_uri(&target_uri));
344+
}
345+
}
346+
_ => {}
327347
}
328348
}
329349
}

0 commit comments

Comments
 (0)