mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-24 11:57:44 +08:00
Merge 5f6953f9c7 into 8eab2fcf5d
This commit is contained in:
commit
3fd2747a28
@ -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
|
||||
}),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user