This commit is contained in:
Lucas Molas 2026-02-12 03:04:21 +01:00 committed by GitHub
commit 3fd2747a28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -646,11 +646,68 @@ func unlinkNodeIfExists(node *core.IpfsNode, path string) error {
type filesLsOutput struct {
Entries []mfs.NodeListing
// Optionally set the path for the recursive listing option.
Path string
}
func listNode(req *cmds.Request, fsNode mfs.FSNode, path string) ([]mfs.NodeListing, error) {
long, _ := req.Options[longOptionName].(bool)
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return nil, err
}
switch fsn := fsNode.(type) {
case *mfs.Directory:
if !long {
var output []mfs.NodeListing
names, err := fsn.ListNames(req.Context)
if err != nil {
return nil, err
}
for _, name := range names {
output = append(output, mfs.NodeListing{
Name: name,
Type: int(fsn.Type()),
})
}
return output, nil
}
listing, err := fsn.List(req.Context)
if err != nil {
return nil, err
}
return listing, nil
case *mfs.File:
// FIXME: `mfs.FSNode` should expose a `Name()` API (it stores the name
// in its inode) and we shouldn't require the path argument here.
_, name := gopath.Split(path)
out := []mfs.NodeListing{{Name: name, Type: int(fsn.Type())}}
if long {
size, err := fsn.Size()
if err != nil {
return nil, err
}
out[0].Size = size
nd, err := fsn.GetNode()
if err != nil {
return nil, err
}
out[0].Hash = enc.Encode(nd.Cid())
}
return out, nil
default:
return nil, errors.New("unrecognized type")
}
}
const (
longOptionName = "long"
dontSortOptionName = "U"
longOptionName = "long"
dontSortOptionName = "U"
filesLsRecursiveOptionName = "recursive"
)
var filesLsCmd = &cmds.Command{
@ -680,6 +737,7 @@ Examples:
Options: []cmds.Option{
cmds.BoolOption(longOptionName, "l", "Use long listing format."),
cmds.BoolOption(dontSortOptionName, "Do not sort; list entries in directory order."),
cmds.BoolOption(filesLsRecursiveOptionName, "R", "List subdirectories recursively.").WithDefault(false),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
var arg string
@ -705,56 +763,59 @@ Examples:
return err
}
long, _ := req.Options[longOptionName].(bool)
enc, err := cmdenv.GetCidEncoder(req)
entries, err := listNode(req, fsn, path)
if err != nil {
return err
}
switch fsn := fsn.(type) {
case *mfs.Directory:
if !long {
var output []mfs.NodeListing
names, err := fsn.ListNames(req.Context)
if err != nil {
return err
}
recursive := req.Options[filesLsRecursiveOptionName].(bool)
if !recursive || mfs.IsFile(fsn) {
return cmds.EmitOnce(res, filesLsOutput{Entries: entries})
}
for _, name := range names {
output = append(output, mfs.NodeListing{
Name: name,
})
}
return cmds.EmitOnce(res, &filesLsOutput{output})
}
listing, err := fsn.List(req.Context)
// Recursive listing directories; mimic Unix `ls -R` behavior (BFS).
listsToProcess := make([]filesLsOutput, 1)
listsToProcess[0] = filesLsOutput{Entries: entries, Path: path}
for len(listsToProcess) > 0 {
listOut := listsToProcess[0]
listsToProcess = listsToProcess[1:]
err = res.Emit(listOut)
if err != nil {
return err
}
return cmds.EmitOnce(res, &filesLsOutput{listing})
case *mfs.File:
_, name := gopath.Split(path)
out := &filesLsOutput{[]mfs.NodeListing{{Name: name}}}
if long {
out.Entries[0].Type = int(fsn.Type())
size, err := fsn.Size()
for _, entry := range listOut.Entries {
if entry.Type != int(mfs.TDir) {
continue
}
dirPath, err := checkPath(listOut.Path)
if err != nil {
return err
}
out.Entries[0].Size = size
if dirPath[len(dirPath)-1] != '/' {
dirPath += "/"
}
dirPath += entry.Name
nd, err := fsn.GetNode()
fsn, err := mfs.Lookup(nd.FilesRoot, dirPath)
if err != nil {
return err
}
out.Entries[0].Hash = enc.Encode(nd.Cid())
childList, err := listNode(req, fsn, dirPath)
if err != nil {
return err
}
listsToProcess = append(listsToProcess,
filesLsOutput{Entries: childList, Path: dirPath})
}
return cmds.EmitOnce(res, out)
default:
return errors.New("unrecognized type")
}
// FIXME(BLOCKING): Evaluate joining this loop with the basic non-recursive case,
// but it might not be worth it adding complexity to the most common basic case.
// (We almost never will list recursively.)
return nil
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *filesLsOutput) error {
@ -766,6 +827,10 @@ Examples:
}
long, _ := req.Options[longOptionName].(bool)
if out.Path != "" {
// We are listing recursively and the listed path is a directory.
fmt.Fprintf(w, "%s:\n", out.Path)
}
for _, o := range out.Entries {
if long {
if o.Type == int(mfs.TDir) {
@ -776,6 +841,9 @@ Examples:
fmt.Fprintf(w, "%s\n", o.Name)
}
}
if out.Path != "" {
fmt.Fprint(w, "\n")
}
return nil
}),