# Expose path in File

**URL:** <https://internals.rust-lang.org/t/expose-path-in-file/21559>\
**Category:** libs\
**Created:** [September 19, 2024, 3:13pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559 "2024-09-19T15:13:55Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![ghost](https://avatars.discourse-cdn.com/v4/letter/g/f04885/32.png) [@ghost](https://internals.rust-lang.org/u/ghost)\
**Post date:** [September 19, 2024, 3:13pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/1 "2024-09-19T15:13:56Z")

</div>

Shouldn't [File](https://doc.rust-lang.org/std/fs/struct.File.html#) struct expose a method to show the underlying path ?

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [September 19, 2024, 3:18pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/2 "2024-09-19T15:18:52Z")

</div>

In systems like Linux, a path is not something that a file has. It's something that can be used to obtain access to a file, but the path may not be the canonical one, and may not even exist afterwards. For example, it's possible to open a `File`, then delete the path (`unlink`), and still read and write from the `File` successfully.

Currently `File` (at least on unix-like systems) is just a thin wrapper over `fd` and takes only 4 bytes, with no allocations on the Rust's side.

---

<div class="post-metadata">

**Author:** ![ryanavella](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryanavella/32/13254_2.png) [@ryanavella](https://internals.rust-lang.org/u/ryanavella)\
**Post date:** [September 19, 2024, 6:16pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/3 "2024-09-19T18:16:47Z")

</div>

If you mean for diagnostic purposes when displaying a `std::io::Error`, there is an [open issue](https://github.com/rust-lang/rfcs/issues/2885) and a [draft PR](https://github.com/rust-lang/rust/pull/86826) showing it should be possible in theory. At this point I think it just needs a dedicated individual to spearhead it.

---

<div class="post-metadata">

**Author:** ![farnz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/farnz/32/6587_2.png) [@farnz](https://internals.rust-lang.org/u/farnz)\
**Post date:** [September 19, 2024, 6:27pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/4 "2024-09-19T18:27:29Z")

</div>

Note that this isn't quite what the original post asked for; the draft PR changes functions like `File::open` and `File::create` to include the path in the error message if they fail, but does not change things like `File::metadata` to include the path.

Basically, the draft PR says "if you passed in a path to this function call, and it fails, give the path back to you as part of the error"; for functions that didn't get a path, there's no path to return to you.

---

<div class="post-metadata">

**Author:** ![ryanavella](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryanavella/32/13254_2.png) [@ryanavella](https://internals.rust-lang.org/u/ryanavella)\
**Post date:** [September 19, 2024, 6:43pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/5 "2024-09-19T18:43:10Z")

</div>

> [@farnz](#):
>
> for functions that didn't get a path, there's no path to return to you.

That's fair, and even on an OS where it can be retrieved after being discarded, I don't think users would be happy with the extra syscall during error generation.

If OP really wants it unconditionally available on `File`, the method either needs to return `Option<PathBuf>` (and have the docs clarify it is not a zero-cost getter) or it needs to be a method on something more like `std::os::windows::fs::FileExt`.

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [September 19, 2024, 7:01pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/6 "2024-09-19T19:01:43Z")

</div>

One can also create `File`s from non-files (on Unices at least).

```rust
fn main() -> Result<(), Box<dyn Error>> {
    let file = File::from(io::stdout().as_fd().try_clone_to_owned()?);
    writeln!(&file, "unbuffered")?;
    Ok(())
}

```

> **[Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f37ae012aef4a4e7fbbcf9d0ce3638e9)**
>
> A browser interface to the Rust compiler to experiment with the language

---

<div class="post-metadata">

**Author:** ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)\
**Post date:** [September 19, 2024, 7:35pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/7 "2024-09-19T19:35:00Z")

</div>

On Linux you can technically retrieve this information, via reading the symlink target path of `/proc/self/fd/N` where N is the fd number.

Of course, it might not be an actual file, or a file that still exists. And /proc may not be mounted. And even if everything works OK, that is still an overhead of a syscall, plus parsing logic to determine what sort of path it is.

So I don't think std should do this (especially since I don't know if you can even do this on other Unices).

---

<div class="post-metadata">

**Author:** ![ryanavella](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryanavella/32/13254_2.png) [@ryanavella](https://internals.rust-lang.org/u/ryanavella)\
**Post date:** [September 19, 2024, 8:03pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/8 "2024-09-19T20:03:54Z")

</div>

> [@Vorpal](#):
>
> So I don't think std should do this (especially since I don't know if you can even do this on other Unices).

`procfs` is available on some Unices, but it is a Linux-ism and so usually not a part of the base system. You can query a file descriptors path on macOS (through a `fcntl` flag) and FreeBSD (through a `sysctl`) but I'm less sure about NetBSD or OpenBSD. A quick google search leads me to believe that OpenBSD has intentionally not provided such an API.

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jrose/32/9591_2.png) [@jrose](https://internals.rust-lang.org/u/jrose)\
**Post date:** [September 19, 2024, 10:15pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/9 "2024-09-19T22:15:55Z")

</div>

It might be a useful _fallible_ API, abstracting over platform differences. But then you need the list of reasons why it’s probably not a good idea for most clients, and at that point it probably doesn’t need to be in std at all. A crate can collect all the approaches just as well.

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [September 21, 2024, 1:41am UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/10 "2024-09-21T01:41:21Z")

</div>

> [@ryanavella](#):
>
> `procfs` is available on some Unices, but it is a Linux-ism

nit: actually it originated on plan9, and linux copied it (with some modification) from there (it did a similar thing with FUSE)

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [September 23, 2024, 12:54pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/11 "2024-09-23T12:54:21Z")

</div>

> [@Vorpal](#):
>
> On Linux you can technically retrieve this information, via reading the symlink target path of `/proc/self/fd/N` where N is the fd number.

Other than the issues listed already, I've played with this before. `/proc` is…a strange place\[1\]. If you delete a file, the symlink's target is updated to have a "` (deleted)`" suffix. If you then make _this_ file, the `readlink` target exits, but it cannot be read via the symlink (because the kernel knows it is not readable). You can therefore detect whether tools read the symlink or do their own `readlink` following internally based on whether such paths "work" for them.

* * *

1. Cue the Monty Python's Knights of the Roundtable scene.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [September 23, 2024, 3:56pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/12 "2024-09-23T15:56:40Z")

</div>

it also doesn't work for files in deeply nested directories when it exceeds PATH\_MAX

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [September 23, 2024, 4:33pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/13 "2024-09-23T16:33:11Z")

</div>

Ah, that reminds me that mount namespaces can differ and the `realpath` go somewhere completely different even if it resolves. All one can really do is `open()` the path itself and not treat them like symlinks at all.

---

<div class="post-metadata">

**Author:** ![ghost](https://avatars.discourse-cdn.com/v4/letter/g/f04885/32.png) [@ghost](https://internals.rust-lang.org/u/ghost)\
**Post date:** [October 4, 2024, 3:18am UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/14 "2024-10-04T03:18:38Z")

</div>

[Debug](https://doc.rust-lang.org/src/std/sys/pal/unix/fs.rs.html#1478) implementation for File has [get\_path](https://doc.rust-lang.org/src/std/sys/pal/unix/fs.rs.html#1481)() which returns Option, may be we can make it public ?

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [October 4, 2024, 7:03pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/15 "2024-10-04T19:03:49Z")

</div>

I think it's been delegated to `Debug` only, because the function is unreliable, and has many platform-specific limitations.

```rust
        fn get_path(_fd: c_int) -> Option<PathBuf> {
            // FIXME(#24570): implement this for other Unix platforms
            None
        }

```

If this kinda mostly worked on Linux, I expect Rust programs would suffer [Hyrum's Law](https://www.hyrumslaw.com). If it's public, people will use it. If it mostly works, people will rely on it. And then it will annoyingly break in some situations on some platforms where someone uses it in an argument to `Command` or saves as a path in config file.

I think `io::Error` could carry a path in cases where it's available via arguments to the function that failed, and that would fix a lot of complaints. For other cases, just carry `(File, PathBuf)` explicitly.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [March 28, 2026, 7:04pm UTC](https://internals.rust-lang.org/t/expose-path-in-file/21559/16 "2026-03-28T19:04:07Z")

</div>

Closed on March 28, 2026, 7:04pm UTC

This topic was automatically closed 540 days after the last reply. New replies are no longer allowed.
