mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-11 09:51:26 -10:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16e1e77068 | ||
|
|
1cfa694aa2 | ||
|
|
5898877136 | ||
|
|
a7d8cac565 |
No files matched your search
@@ -32,7 +32,7 @@ func PrintCanaries(con *console.SliverClient, canaries []*clientpb.DNSCanary, bu
|
||||
tw := table.NewWriter()
|
||||
tw.SetStyle(settings.GetTableStyle(con))
|
||||
tw.AppendHeader(table.Row{
|
||||
"Sliver Name",
|
||||
"Implant Name",
|
||||
"Domain",
|
||||
"Triggered",
|
||||
"First Trigger",
|
||||
|
||||
@@ -22,7 +22,8 @@ var (
|
||||
// GenerateBeaconCmd - The main command used to generate implant binaries
|
||||
func GenerateBeaconCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
if shouldRunGenerateBeaconForm(cmd, con, args) {
|
||||
result, err := forms.GenerateBeaconForm()
|
||||
compiler, _ := compilerTargets(con)
|
||||
result, err := forms.GenerateBeaconForm(compiler)
|
||||
if err != nil {
|
||||
if errors.Is(err, forms.ErrUserAborted) {
|
||||
return
|
||||
|
||||
@@ -91,7 +91,8 @@ var (
|
||||
// GenerateCmd - The main command used to generate implant binaries
|
||||
func GenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
if shouldRunGenerateForm(cmd, con, args) {
|
||||
result, err := forms.GenerateForm()
|
||||
compiler, _ := compilerTargets(con)
|
||||
result, err := forms.GenerateForm(compiler)
|
||||
if err != nil {
|
||||
if errors.Is(err, forms.ErrUserAborted) {
|
||||
return
|
||||
@@ -118,14 +119,15 @@ func GenerateCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
|
||||
} else {
|
||||
_, err := externalBuild(name, config, save, con)
|
||||
if err != nil {
|
||||
if err == ErrNoExternalBuilder {
|
||||
switch err {
|
||||
case ErrNoExternalBuilder:
|
||||
con.PrintErrorf("There are no external builders currently connected to the server\n")
|
||||
con.PrintErrorf("See 'builders' command for more information\n")
|
||||
} else if err == ErrNoValidBuilders {
|
||||
case ErrNoValidBuilders:
|
||||
con.PrintErrorf("There are external builders connected to the server, but none can build the target you specified\n")
|
||||
con.PrintErrorf("Invalid target %s\n", fmt.Sprintf("%s:%s/%s", config.Format, config.GOOS, config.GOARCH))
|
||||
con.PrintErrorf("See 'builders' command for more information\n")
|
||||
} else {
|
||||
default:
|
||||
con.PrintErrorf("%s\n", err)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -124,7 +124,7 @@ func PrintImplantBuilds(builds *clientpb.ImplantBuilds, filters ImplantBuildFilt
|
||||
config.Format,
|
||||
strings.Join(c2URLs, "\n"),
|
||||
fmt.Sprintf("%v", config.Debug),
|
||||
fmt.Sprintf(config.HTTPC2ConfigName),
|
||||
fmt.Sprintf("%s", config.HTTPC2ConfigName),
|
||||
fmt.Sprintf("%v", builds.ResourceIDs[sliverName].Value),
|
||||
fmt.Sprintf("%v", builds.Staged[sliverName]),
|
||||
})
|
||||
|
||||
@@ -263,6 +263,19 @@ func (con *SliverClient) runRCLine(serverCmds, sliverCmds console.Commands, line
|
||||
return fmt.Errorf("parse error: %w", err)
|
||||
}
|
||||
|
||||
if con.serverCmds == nil {
|
||||
con.serverCmds = serverCmds
|
||||
}
|
||||
if con.sliverCmds == nil {
|
||||
con.sliverCmds = sliverCmds
|
||||
}
|
||||
|
||||
menu := con.App.ActiveMenu()
|
||||
if menu != nil {
|
||||
// Reset per line to avoid stale roots when rc scripts switch menus.
|
||||
menu.Command = nil
|
||||
}
|
||||
|
||||
for _, hook := range con.App.PreCmdRunLineHooks {
|
||||
args, err = hook(args)
|
||||
if err != nil {
|
||||
@@ -274,15 +287,13 @@ func (con *SliverClient) runRCLine(serverCmds, sliverCmds console.Commands, line
|
||||
return nil
|
||||
}
|
||||
|
||||
if con.serverCmds == nil {
|
||||
con.serverCmds = serverCmds
|
||||
menu = con.App.ActiveMenu()
|
||||
if menu == nil {
|
||||
return fmt.Errorf("no active menu")
|
||||
}
|
||||
if con.sliverCmds == nil {
|
||||
con.sliverCmds = sliverCmds
|
||||
if menu.Command == nil {
|
||||
con.setMenuCommand(menu, args)
|
||||
}
|
||||
|
||||
menu := con.App.ActiveMenu()
|
||||
con.setMenuCommand(menu, args)
|
||||
if menu.Command == nil {
|
||||
return fmt.Errorf("no commands available")
|
||||
}
|
||||
|
||||
+30
-34
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/charmbracelet/huh"
|
||||
)
|
||||
@@ -23,62 +24,57 @@ type GenerateFormResult struct {
|
||||
}
|
||||
|
||||
// GenerateForm prompts for core generate flags and returns the collected values.
|
||||
func GenerateForm() (*GenerateFormResult, error) {
|
||||
func GenerateForm(compiler *clientpb.Compiler) (*GenerateFormResult, error) {
|
||||
result := &GenerateFormResult{
|
||||
OS: "windows",
|
||||
Arch: "amd64",
|
||||
Format: "exe",
|
||||
C2Type: "mtls",
|
||||
}
|
||||
commonPlatformsOnly := true
|
||||
lastCommonPlatformsOnly := commonPlatformsOnly
|
||||
compilerTargets := compilerTargetList(compiler)
|
||||
targetBindings := &targetOptionBindings{
|
||||
Common: &commonPlatformsOnly,
|
||||
OS: &result.OS,
|
||||
Arch: &result.Arch,
|
||||
}
|
||||
|
||||
form := huh.NewForm(
|
||||
huh.NewGroup(
|
||||
huh.NewConfirm().
|
||||
Title("Common Platforms Only").
|
||||
Value(&commonPlatformsOnly),
|
||||
huh.NewSelect[string]().
|
||||
Title("Target operating system").
|
||||
Options(
|
||||
huh.NewOption("Windows", "windows"),
|
||||
huh.NewOption("Linux", "linux"),
|
||||
huh.NewOption("macOS", "darwin"),
|
||||
).
|
||||
OptionsFunc(func() []huh.Option[string] {
|
||||
maybeResetTargets(commonPlatformsOnly, &lastCommonPlatformsOnly, compilerTargets, &result.OS, &result.Arch, &result.Format)
|
||||
if commonPlatformsOnly || len(compilerTargets) == 0 {
|
||||
return commonOSOptions()
|
||||
}
|
||||
return osOptionsFromTargets(compilerTargets)
|
||||
}, targetBindings).
|
||||
Value(&result.OS),
|
||||
huh.NewSelect[string]().
|
||||
Title("CPU architecture").
|
||||
OptionsFunc(func() []huh.Option[string] {
|
||||
switch result.OS {
|
||||
case "darwin":
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("arm64", "arm64"),
|
||||
}
|
||||
case "linux":
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("386", "386"),
|
||||
}
|
||||
default:
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("386", "386"),
|
||||
}
|
||||
maybeResetTargets(commonPlatformsOnly, &lastCommonPlatformsOnly, compilerTargets, &result.OS, &result.Arch, &result.Format)
|
||||
if commonPlatformsOnly || len(compilerTargets) == 0 {
|
||||
return commonArchOptions(result.OS)
|
||||
}
|
||||
}, &result.OS).
|
||||
return archOptionsFromTargets(compilerTargets, result.OS)
|
||||
}, targetBindings).
|
||||
Height(3).
|
||||
Value(&result.Arch),
|
||||
huh.NewSelect[string]().
|
||||
Title("Output format").
|
||||
OptionsFunc(func() []huh.Option[string] {
|
||||
options := []huh.Option[string]{
|
||||
huh.NewOption("Executable", "exe"),
|
||||
huh.NewOption("Shared library", "shared"),
|
||||
maybeResetTargets(commonPlatformsOnly, &lastCommonPlatformsOnly, compilerTargets, &result.OS, &result.Arch, &result.Format)
|
||||
if commonPlatformsOnly || len(compilerTargets) == 0 {
|
||||
return commonFormatOptions(result.OS)
|
||||
}
|
||||
if result.OS == "windows" {
|
||||
options = append(options,
|
||||
huh.NewOption("Service", "service"),
|
||||
huh.NewOption("Shellcode", "shellcode"),
|
||||
)
|
||||
}
|
||||
return options
|
||||
}, &result.OS).
|
||||
return formatOptionsFromTargets(compilerTargets, result.OS, result.Arch)
|
||||
}, targetBindings).
|
||||
Height(3).
|
||||
Value(&result.Format),
|
||||
),
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/util"
|
||||
"github.com/charmbracelet/huh"
|
||||
)
|
||||
@@ -26,62 +27,57 @@ type GenerateBeaconFormResult struct {
|
||||
}
|
||||
|
||||
// GenerateBeaconForm prompts for generate beacon flags and returns the collected values.
|
||||
func GenerateBeaconForm() (*GenerateBeaconFormResult, error) {
|
||||
func GenerateBeaconForm(compiler *clientpb.Compiler) (*GenerateBeaconFormResult, error) {
|
||||
result := &GenerateBeaconFormResult{
|
||||
OS: "windows",
|
||||
Arch: "amd64",
|
||||
Format: "exe",
|
||||
C2Type: "mtls",
|
||||
}
|
||||
commonPlatformsOnly := true
|
||||
lastCommonPlatformsOnly := commonPlatformsOnly
|
||||
compilerTargets := compilerTargetList(compiler)
|
||||
targetBindings := &targetOptionBindings{
|
||||
Common: &commonPlatformsOnly,
|
||||
OS: &result.OS,
|
||||
Arch: &result.Arch,
|
||||
}
|
||||
|
||||
form := huh.NewForm(
|
||||
huh.NewGroup(
|
||||
huh.NewConfirm().
|
||||
Title("Common Platforms Only").
|
||||
Value(&commonPlatformsOnly),
|
||||
huh.NewSelect[string]().
|
||||
Title("Target operating system").
|
||||
Options(
|
||||
huh.NewOption("Windows", "windows"),
|
||||
huh.NewOption("Linux", "linux"),
|
||||
huh.NewOption("macOS", "darwin"),
|
||||
).
|
||||
OptionsFunc(func() []huh.Option[string] {
|
||||
maybeResetTargets(commonPlatformsOnly, &lastCommonPlatformsOnly, compilerTargets, &result.OS, &result.Arch, &result.Format)
|
||||
if commonPlatformsOnly || len(compilerTargets) == 0 {
|
||||
return commonOSOptions()
|
||||
}
|
||||
return osOptionsFromTargets(compilerTargets)
|
||||
}, targetBindings).
|
||||
Value(&result.OS),
|
||||
huh.NewSelect[string]().
|
||||
Title("CPU architecture").
|
||||
OptionsFunc(func() []huh.Option[string] {
|
||||
switch result.OS {
|
||||
case "darwin":
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("arm64", "arm64"),
|
||||
}
|
||||
case "linux":
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("386", "386"),
|
||||
}
|
||||
default:
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("386", "386"),
|
||||
}
|
||||
maybeResetTargets(commonPlatformsOnly, &lastCommonPlatformsOnly, compilerTargets, &result.OS, &result.Arch, &result.Format)
|
||||
if commonPlatformsOnly || len(compilerTargets) == 0 {
|
||||
return commonArchOptions(result.OS)
|
||||
}
|
||||
}, &result.OS).
|
||||
return archOptionsFromTargets(compilerTargets, result.OS)
|
||||
}, targetBindings).
|
||||
Height(3).
|
||||
Value(&result.Arch),
|
||||
huh.NewSelect[string]().
|
||||
Title("Output format").
|
||||
OptionsFunc(func() []huh.Option[string] {
|
||||
options := []huh.Option[string]{
|
||||
huh.NewOption("Executable", "exe"),
|
||||
huh.NewOption("Shared library", "shared"),
|
||||
maybeResetTargets(commonPlatformsOnly, &lastCommonPlatformsOnly, compilerTargets, &result.OS, &result.Arch, &result.Format)
|
||||
if commonPlatformsOnly || len(compilerTargets) == 0 {
|
||||
return commonFormatOptions(result.OS)
|
||||
}
|
||||
if result.OS == "windows" {
|
||||
options = append(options,
|
||||
huh.NewOption("Service", "service"),
|
||||
huh.NewOption("Shellcode", "shellcode"),
|
||||
)
|
||||
}
|
||||
return options
|
||||
}, &result.OS).
|
||||
return formatOptionsFromTargets(compilerTargets, result.OS, result.Arch)
|
||||
}, targetBindings).
|
||||
Height(3).
|
||||
Value(&result.Format),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
package forms
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/charmbracelet/huh"
|
||||
)
|
||||
|
||||
type formatOption struct {
|
||||
format clientpb.OutputFormat
|
||||
label string
|
||||
value string
|
||||
}
|
||||
|
||||
type targetOptionBindings struct {
|
||||
Common *bool
|
||||
OS *string
|
||||
Arch *string
|
||||
}
|
||||
|
||||
var formatOptionOrder = []formatOption{
|
||||
{format: clientpb.OutputFormat_EXECUTABLE, label: "Executable", value: "exe"},
|
||||
{format: clientpb.OutputFormat_SHARED_LIB, label: "Shared library", value: "shared"},
|
||||
{format: clientpb.OutputFormat_SERVICE, label: "Service", value: "service"},
|
||||
{format: clientpb.OutputFormat_SHELLCODE, label: "Shellcode", value: "shellcode"},
|
||||
}
|
||||
|
||||
func commonOSOptions() []huh.Option[string] {
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("Windows", "windows"),
|
||||
huh.NewOption("Linux", "linux"),
|
||||
huh.NewOption("macOS", "darwin"),
|
||||
}
|
||||
}
|
||||
|
||||
func commonArchOptions(goos string) []huh.Option[string] {
|
||||
switch goos {
|
||||
case "darwin":
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("arm64", "arm64"),
|
||||
}
|
||||
case "linux":
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("386", "386"),
|
||||
}
|
||||
default:
|
||||
return []huh.Option[string]{
|
||||
huh.NewOption("amd64", "amd64"),
|
||||
huh.NewOption("386", "386"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func commonFormatOptions(goos string) []huh.Option[string] {
|
||||
options := []huh.Option[string]{
|
||||
huh.NewOption("Executable", "exe"),
|
||||
huh.NewOption("Shared library", "shared"),
|
||||
}
|
||||
if goos == "windows" {
|
||||
options = append(options,
|
||||
huh.NewOption("Service", "service"),
|
||||
huh.NewOption("Shellcode", "shellcode"),
|
||||
)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func firstOptionValue(options []huh.Option[string]) (string, bool) {
|
||||
if len(options) == 0 {
|
||||
return "", false
|
||||
}
|
||||
return options[0].Value, true
|
||||
}
|
||||
|
||||
func maybeResetTargets(commonPlatformsOnly bool, lastCommonPlatformsOnly *bool, compilerTargets []*clientpb.CompilerTarget, goos, goarch, format *string) {
|
||||
if lastCommonPlatformsOnly == nil || goos == nil || goarch == nil || format == nil {
|
||||
return
|
||||
}
|
||||
if commonPlatformsOnly == *lastCommonPlatformsOnly {
|
||||
return
|
||||
}
|
||||
*lastCommonPlatformsOnly = commonPlatformsOnly
|
||||
if commonPlatformsOnly {
|
||||
return
|
||||
}
|
||||
|
||||
osOptions := commonOSOptions()
|
||||
if len(compilerTargets) > 0 {
|
||||
osOptions = osOptionsFromTargets(compilerTargets)
|
||||
if len(osOptions) == 0 {
|
||||
osOptions = commonOSOptions()
|
||||
}
|
||||
}
|
||||
if value, ok := firstOptionValue(osOptions); ok {
|
||||
*goos = value
|
||||
}
|
||||
|
||||
archOptions := commonArchOptions(*goos)
|
||||
if len(compilerTargets) > 0 {
|
||||
archOptions = archOptionsFromTargets(compilerTargets, *goos)
|
||||
if len(archOptions) == 0 {
|
||||
archOptions = commonArchOptions(*goos)
|
||||
}
|
||||
}
|
||||
if value, ok := firstOptionValue(archOptions); ok {
|
||||
*goarch = value
|
||||
}
|
||||
|
||||
formatOptions := commonFormatOptions(*goos)
|
||||
if len(compilerTargets) > 0 {
|
||||
formatOptions = formatOptionsFromTargets(compilerTargets, *goos, *goarch)
|
||||
if len(formatOptions) == 0 {
|
||||
formatOptions = commonFormatOptions(*goos)
|
||||
}
|
||||
}
|
||||
if value, ok := firstOptionValue(formatOptions); ok {
|
||||
*format = value
|
||||
}
|
||||
}
|
||||
|
||||
func compilerTargetList(compiler *clientpb.Compiler) []*clientpb.CompilerTarget {
|
||||
if compiler == nil {
|
||||
return nil
|
||||
}
|
||||
targets := make([]*clientpb.CompilerTarget, 0, len(compiler.Targets)+len(compiler.UnsupportedTargets))
|
||||
targets = append(targets, compiler.Targets...)
|
||||
targets = append(targets, compiler.UnsupportedTargets...)
|
||||
return targets
|
||||
}
|
||||
|
||||
func osOptionsFromTargets(targets []*clientpb.CompilerTarget) []huh.Option[string] {
|
||||
if len(targets) == 0 {
|
||||
return nil
|
||||
}
|
||||
seen := map[string]struct{}{}
|
||||
for _, target := range targets {
|
||||
if target.GOOS == "" {
|
||||
continue
|
||||
}
|
||||
seen[target.GOOS] = struct{}{}
|
||||
}
|
||||
values := make([]string, 0, len(seen))
|
||||
for value := range seen {
|
||||
values = append(values, value)
|
||||
}
|
||||
sort.Strings(values)
|
||||
|
||||
options := make([]huh.Option[string], 0, len(values))
|
||||
for _, value := range values {
|
||||
options = append(options, huh.NewOption(osLabel(value), value))
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func archOptionsFromTargets(targets []*clientpb.CompilerTarget, goos string) []huh.Option[string] {
|
||||
if len(targets) == 0 {
|
||||
return nil
|
||||
}
|
||||
seen := map[string]struct{}{}
|
||||
for _, target := range targets {
|
||||
if goos != "" && target.GOOS != goos {
|
||||
continue
|
||||
}
|
||||
if target.GOARCH == "" {
|
||||
continue
|
||||
}
|
||||
seen[target.GOARCH] = struct{}{}
|
||||
}
|
||||
values := make([]string, 0, len(seen))
|
||||
for value := range seen {
|
||||
values = append(values, value)
|
||||
}
|
||||
sort.Strings(values)
|
||||
|
||||
options := make([]huh.Option[string], 0, len(values))
|
||||
for _, value := range values {
|
||||
options = append(options, huh.NewOption(value, value))
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func formatOptionsFromTargets(targets []*clientpb.CompilerTarget, goos, goarch string) []huh.Option[string] {
|
||||
if len(targets) == 0 {
|
||||
return nil
|
||||
}
|
||||
available := map[clientpb.OutputFormat]struct{}{}
|
||||
for _, target := range targets {
|
||||
if goos != "" && target.GOOS != goos {
|
||||
continue
|
||||
}
|
||||
if goarch != "" && target.GOARCH != goarch {
|
||||
continue
|
||||
}
|
||||
available[target.Format] = struct{}{}
|
||||
}
|
||||
|
||||
options := make([]huh.Option[string], 0, len(available))
|
||||
for _, option := range formatOptionOrder {
|
||||
if _, ok := available[option.format]; ok {
|
||||
options = append(options, huh.NewOption(option.label, option.value))
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func osLabel(value string) string {
|
||||
switch value {
|
||||
case "windows":
|
||||
return "Windows"
|
||||
case "linux":
|
||||
return "Linux"
|
||||
case "darwin":
|
||||
return "macOS"
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
@@ -166,10 +166,14 @@ func dirListHandler(data []byte, resp RPCResponse) {
|
||||
dirList.Exists = true
|
||||
} else {
|
||||
dirList.Exists = false
|
||||
dirList.Response = &commonpb.Response{Err: err.Error()}
|
||||
}
|
||||
dirList.Files = []*sliverpb.FileInfo{}
|
||||
rootDirInfo, err := rootDirEntry.Info()
|
||||
if err == nil && filter == "" {
|
||||
var rootDirInfo fs.FileInfo
|
||||
if rootDirEntry != nil {
|
||||
rootDirInfo, err = rootDirEntry.Info()
|
||||
}
|
||||
if err == nil && rootDirInfo != nil && filter == "" {
|
||||
// We should not get an error because we created the DirEntry object from the FileInfo object
|
||||
dirList.Files = append(dirList.Files, &sliverpb.FileInfo{
|
||||
Name: ".", // Cannot use the name from the FileInfo / DirEntry because that is the name of the directory
|
||||
@@ -193,6 +197,7 @@ func dirListHandler(data []byte, resp RPCResponse) {
|
||||
if err != nil {
|
||||
// Then this is a bad filter, and it will be a bad filter
|
||||
// on every iteration of the loop, so we might as well break now
|
||||
dirList.Response = &commonpb.Response{Err: err.Error()}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -249,22 +254,26 @@ func getDirList(target string) (string, fs.DirEntry, []fs.DirEntry, error) {
|
||||
// {{end}}
|
||||
return "", nil, nil, err
|
||||
}
|
||||
if rootInfo, err := os.Stat(dir); !os.IsNotExist(err) {
|
||||
/*
|
||||
We could place the entry for the directory itself
|
||||
at the beginning of the returned slice of DirEntry
|
||||
objects, but then it is not clear if that is the
|
||||
root directory or a directory / file in the root
|
||||
directory with the same name as the root directory.
|
||||
|
||||
Using WalkDir is not great here because you cannot
|
||||
tell it to not be recursive, so we will be wasting
|
||||
cycles telling it to skip directories and files
|
||||
*/
|
||||
files, err := os.ReadDir(dir)
|
||||
return dir, fs.FileInfoToDirEntry(rootInfo), files, err
|
||||
rootInfo, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return dir, nil, []fs.DirEntry{}, errors.New("directory does not exist")
|
||||
}
|
||||
return dir, nil, []fs.DirEntry{}, err
|
||||
}
|
||||
return dir, nil, []fs.DirEntry{}, errors.New("directory does not exist")
|
||||
/*
|
||||
We could place the entry for the directory itself
|
||||
at the beginning of the returned slice of DirEntry
|
||||
objects, but then it is not clear if that is the
|
||||
root directory or a directory / file in the root
|
||||
directory with the same name as the root directory.
|
||||
|
||||
Using WalkDir is not great here because you cannot
|
||||
tell it to not be recursive, so we will be wasting
|
||||
cycles telling it to skip directories and files
|
||||
*/
|
||||
files, err := os.ReadDir(dir)
|
||||
return dir, fs.FileInfoToDirEntry(rootInfo), files, err
|
||||
}
|
||||
|
||||
func rmHandler(data []byte, resp RPCResponse) {
|
||||
|
||||
Reference in new issue
Block a user