You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
package os
// ReadDir reads the named directory in the root,// returning all its directory entries sorted by filename.// See [ReadDir] for more details.func (r*Root) ReadDir(namestring) ([]DirEntry, error)
This is a convenience method, like Root.ReadFile and Root.WriteFile (#73126). I propose adding it because:
os.ReadDir is a useful convenience function, and it is useful to have an equivalent that works directly with os.Root.
The io/fs package includes both ReadDir and the ReadDirFS interface, suggesting that directory listing is core filesystem functionality.
fs.ReadDir(r.FS(), name) uses io/fs path syntax, while methods on Root accept native os path syntax.
This method was considered during the original Root proposal and explicitly left as a possible follow-up (#67002 (comment)).
This gap has also appeared in practice: apko explicitly notes that *os.Root does not expose ReadDir and works around it using Root.Open followed by File.ReadDir.
I recently hit a usage bug with os.Root where os.Root.FS() was used with io/fs.ReadDir. Accessing files via an fs.FS enforces path naming restrictions (valid UTF-8) that don't apply on the underlying filesystems. This prevented the tooling from managing oddly named files under the root.
Had os.Root.ReadDir existed it would have been used instead and avoided the bug.
The other common convenience functions exist, I think ReadDir should be added too.
I find ReadDir is the better choice out of the 3 options (faster, only pay for what you need) -- io/fs made the same choice with that API. os.Root is a new API too, I think it would similarly make sense to support ReadDir.
I don't have a good reason to use Readdir or Readdirnames anymore - I wouldn't miss them if they weren't there. I'll let others advocate for them if desired, but the single API offers less confusion than all 3.
It seems like the logical conclusion of proposals like this is that os.Root eventually grows to have a method for every function in os which takes a filesystem path as an argument, with equivalent meaning except that the filesystem path is interpreted relative to the root and constrained to it instead of relative to cwd and unconstrained.
Is there some specific rule dividing os functions which are echoed as os.Root methods from those that aren't? Ideally this would be a policy set just once and applied automatically to anything new added to package os in future, rather than arguing each function individually when these Root-based methods have essentially the same use-cases as the package-level functions. 🤔
IIRC, the initial set of os.Root methods was every filesystem operation in os that operates on a path and couldn't be emulated by some other mechanism.
So Root.Chtimes exists because os.Chtimes exists. Root.Chmod exists because, while File.Chmod does exist, it requires that you have the ability to open a file before you can operate on it and isn't a perfect substitute. Root.Truncate does not exist, because you can get the same results with other operations.
There isn't any rule about what else gets added. Perhaps we should have one. What os functions operating on files are left that don't have an os.Root equivalent? From a quick scan, I see MkdirTemp, ReadDir, TempDir, and Truncate. I might have overlooked some.
I deliberately left Truncate out; see #67002 (comment). (tl;dr, I think the only reason Truncate exists is because Unix has a truncate(2) syscall, there is no equivalent path-scoped syscall, and you can easily truncate a file using other mechanisms.)
Root.ReadDir seems pretty reasonable.
I don't have much opinion on whether MkdirTemp and TempDir should exist on Root. Maybe, as the only remaining top-level functions that don't? And at that point, maybe we should add Root.Truncate for completeness?
Activity
ianlancetaylor commentedon Sep 14, 2026
CC @neild
mpx commentedon Sep 16, 2026
I recently hit a usage bug with
os.Rootwhereos.Root.FS()was used withio/fs.ReadDir. Accessing files via anfs.FSenforces path naming restrictions (valid UTF-8) that don't apply on the underlying filesystems. This prevented the tooling from managing oddly named files under the root.Had
os.Root.ReadDirexisted it would have been used instead and avoided the bug.The other common convenience functions exist, I think
ReadDirshould be added too.neild commentedon Sep 16, 2026
Why
ReadDirand not alsoReaddirandReaddirnames?mpx commentedon Sep 16, 2026
I find
ReadDiris the better choice out of the 3 options (faster, only pay for what you need) --io/fsmade the same choice with that API.os.Rootis a new API too, I think it would similarly make sense to supportReadDir.I don't have a good reason to use
ReaddirorReaddirnamesanymore - I wouldn't miss them if they weren't there. I'll let others advocate for them if desired, but the single API offers less confusion than all 3.apparentlymart commentedon Sep 16, 2026
It seems like the logical conclusion of proposals like this is that
os.Rooteventually grows to have a method for every function inoswhich takes a filesystem path as an argument, with equivalent meaning except that the filesystem path is interpreted relative to the root and constrained to it instead of relative to cwd and unconstrained.Is there some specific rule dividing
osfunctions which are echoed asos.Rootmethods from those that aren't? Ideally this would be a policy set just once and applied automatically to anything new added topackage osin future, rather than arguing each function individually when theseRoot-based methods have essentially the same use-cases as the package-level functions. 🤔neild commentedon Sep 16, 2026
IIRC, the initial set of
os.Rootmethods was every filesystem operation inosthat operates on a path and couldn't be emulated by some other mechanism.So
Root.Chtimesexists becauseos.Chtimesexists.Root.Chmodexists because, whileFile.Chmoddoes exist, it requires that you have the ability to open a file before you can operate on it and isn't a perfect substitute.Root.Truncatedoes not exist, because you can get the same results with other operations.There isn't any rule about what else gets added. Perhaps we should have one. What
osfunctions operating on files are left that don't have anos.Rootequivalent? From a quick scan, I seeMkdirTemp,ReadDir,TempDir, andTruncate. I might have overlooked some.I deliberately left
Truncateout; see #67002 (comment). (tl;dr, I think the only reasonTruncateexists is because Unix has a truncate(2) syscall, there is no equivalent path-scoped syscall, and you can easily truncate a file using other mechanisms.)Root.ReadDirseems pretty reasonable.I don't have much opinion on whether
MkdirTempandTempDirshould exist onRoot. Maybe, as the only remaining top-level functions that don't? And at that point, maybe we should addRoot.Truncatefor completeness?