Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

io/fs: document how hard and symbolic links in a fs.FS should work #45470

SlyMarbo opened this issue Apr 9, 2021 · 3 comments

io/fs: document how hard and symbolic links in a fs.FS should work #45470

SlyMarbo opened this issue Apr 9, 2021 · 3 comments


Copy link

@SlyMarbo SlyMarbo commented Apr 9, 2021

What version of Go are you using (go version)?

$ go version
go version go1.16.3 darwin/amd64

Does this issue reproduce with the latest release?


What did you do?

Write code to present a TAR archive as a fs.FS. TAR archives support hard and symbolic links, but nothing in this issue is specific to TAR.

What did you expect to see?

Documentation on how an fs.FS should behave when hard and symbolic links exist. testing/fstest.TestFS checks some of these behaviours, but it's not clear exactly how this should work.

Hard links

Given a filesystem:

/a    (hard link to /b)

It seems reasonable to assume that any fs.FS APIs called with the path "a" would return the answers for "b", but with the name "a". That is:

  • Calling fs.Stat(fsys, "a") would return a fs.FileInfo where calling Name() would return "a", but its other methods would return the details from "b"
  • Calling fs.ReadFile(fsys, "a") would return the contents from "b"
  • Calling fs.ReadDir(fsys, ".") would return two fs.DirEntrys, with the names "a" and "b" but otherwise identical details.

Is this assumption correct? Could it be documented?

Symbolic links

Symbolics are a bit more tricky, because the link nature is less hidden than with hard links. Presumably, some APIs should return the details of the link, rather than the details of the file the link points to. fs.FS doesn't separate Stat and Lstat. Does that mean fs.Stat(fsys, "some/path") should behave like os.Stat, returning only the details for the link target? Which file name should be returned? Likewise, how should fs.ReadDir behave? Should the details in a fs.DirEntry representing a symbolic link include the details of the link or the target? What about the fs.FileInfo returned from the directory entry's FileInfo method?

All of this is hard to guess. I'm not particularly concerned which approach is taken, whether symbolic links behave the same as hard links, or whether links are just ignored entirely, but it would be really useful for the behaviour to be documented somewhere, ideally in the docs for fs.FS.

I know this is a tricky and tedious question, so I really appreciate your help.

Copy link

@dmitshur dmitshur commented Apr 9, 2021

As I currently understand this, the fs.FS interface represents an abstract hierarchical file system, and it's up to the implementation to define this. There may be multiple valid implementations that provide different behavior for hard and symbolic links. As a result, it would be outside of scope for io/fs documentation to provide specific guidance.

I did not find hard and symbolic links discussed in the draft design, proposal, nor reddit Q/A.

CC @rsc, @ianlancetaylor, @bcmills.


Copy link

@ulikunitz ulikunitz commented Apr 10, 2021

You got the semantics for hard links correct. Your users might however not be able to find out how many hard links there are for a file. That could be provided by the Sys() method of FileInfo, where you can provide your own custom information.

For symbolic links Stat() must behave like os.Stat() since it might be implemented by Open() if you don't support StatFS(). Note that DirEntry provides information about the symbolic link and not the target file. Information that is missing (target file) can be provided by the Sys() method of FileInfo. However your users might find that quite inconvenient. So I suggest that you provide an extension, maybe called SymFS, supporting Lstat() and Readlink().


Copy link

@SlyMarbo SlyMarbo commented Apr 19, 2021

Yes, that all sounds reasonable. The main thing I found frustrating is that testing/fstest.TestFS has a particular set of expectations that don't necessarily play nicely with symbolic links. For example, it appears to expect that any DirEntry that returns false for IsDir() should return a non-error when Read is called on the fs.File, whereas a DirEntry that returns true for IsDir() should return a non-error when ReadDir is called on the fs.File.

If you have a symbolic link (which isn't a directory, at least according to the TAR archive) that points to a directory, the naive implementation will be failed by testing.fstest.TestFS. At least documenting this behaviour would make it easier to implement correctly. Thanks for the input so far.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants