Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions packages/envd/internal/services/filesystem/dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,14 @@ func walkDir(requestedPath string, dirPath string, depth int) (entries []*rpc.En
return filepath.SkipDir
}

entries = append(entries, &rpc.EntryInfo{
Name: entry.Name(),
Type: getEntryType(entry),
// Return the requested path as the base path instead of the symlink-resolved path
Path: filepath.Join(requestedPath, relPath),
})
fileInfo, err := entry.Info()
if err != nil {
return err
}

// Return the requested path as the base path instead of the symlink-resolved path
path = filepath.Join(requestedPath, relPath)
entries = append(entries, entryInfoFromFileInfo(fileInfo, path))
return nil
})
if err != nil {
Expand Down
6 changes: 1 addition & 5 deletions packages/envd/internal/services/filesystem/move.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ func (Service) Move(ctx context.Context, req *connect.Request[rpc.MoveRequest])
}

return connect.NewResponse(&rpc.MoveResponse{
Entry: &rpc.EntryInfo{
Name: filepath.Base(destination),
Type: getEntryType(entry),
Path: destination,
},
Entry: entryInfoFromFileInfo(entry, destination),
}), nil
}
10 changes: 1 addition & 9 deletions packages/envd/internal/services/filesystem/stat.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,5 @@ func (Service) Stat(ctx context.Context, req *connect.Request[rpc.StatRequest])
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("error statting file: %w", err))
}

return connect.NewResponse(
&rpc.StatResponse{
Entry: &rpc.EntryInfo{
Name: fileInfo.Name(),
Type: getEntryType(fileInfo),
Path: path,
},
},
), nil
return connect.NewResponse(&rpc.StatResponse{Entry: entryInfoFromFileInfo(fileInfo, path)}), nil
}
84 changes: 72 additions & 12 deletions packages/envd/internal/services/filesystem/utils.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,88 @@
package filesystem

import (
"path"
"fmt"
"os"
"os/user"
"syscall"

"google.golang.org/protobuf/types/known/timestamppb"

rpc "github.com/e2b-dev/infra/packages/envd/internal/services/spec/filesystem"
)

type osEntry interface {
IsDir() bool
// getEntryType determines the type of file entry based on its mode and path.
// If the file is a symlink, it follows the symlink to determine the actual type.
func getEntryType(mode os.FileMode) rpc.FileType {
switch {
case mode.IsRegular():
return rpc.FileType_FILE_TYPE_FILE
case mode.IsDir():
return rpc.FileType_FILE_TYPE_DIRECTORY
default:
return rpc.FileType_FILE_TYPE_UNSPECIFIED
}
}

// getFolder returns the path of the directory the entry belongs to.
func getFolder(entry *rpc.EntryInfo) string {
if entry.Type == rpc.FileType_FILE_TYPE_DIRECTORY {
return entry.Path
// getFileOwnership returns the owner and group names for a file.
// If the lookup fails, it returns the numeric UID and GID as strings.
func getFileOwnership(fileInfo os.FileInfo) (owner, group string) {
sys, ok := fileInfo.Sys().(*syscall.Stat_t)
if !ok {
return "", ""
}

// Look up username
owner = fmt.Sprintf("%d", sys.Uid)
if u, err := user.LookupId(owner); err == nil {
owner = u.Username
}

// Look up group name
group = fmt.Sprintf("%d", sys.Gid)
if g, err := user.LookupGroupId(fmt.Sprintf("%d", sys.Gid)); err == nil {
group = g.Name
}

return path.Dir(entry.Path)
return owner, group
}

func getEntryType(entry osEntry) rpc.FileType {
if entry.IsDir() {
return rpc.FileType_FILE_TYPE_DIRECTORY
func entryInfoFromFileInfo(fileInfo os.FileInfo, path string) *rpc.EntryInfo {
owner, group := getFileOwnership(fileInfo)
fileMode := fileInfo.Mode()

var symlinkTarget *string
if fileMode&os.ModeSymlink != 0 {
// If we can't resolve the symlink target, we won't set the target
target, err := followSymlink(path)
if err == nil {
symlinkTarget = &target
}
}

var entryType rpc.FileType
if symlinkTarget == nil {
entryType = getEntryType(fileMode)
} else {
return rpc.FileType_FILE_TYPE_FILE
// If it's a symlink, we need to determine the type of the target
targetInfo, err := os.Stat(*symlinkTarget)
if err != nil {
entryType = rpc.FileType_FILE_TYPE_UNSPECIFIED
} else {
entryType = getEntryType(targetInfo.Mode())
}
}

return &rpc.EntryInfo{
Name: fileInfo.Name(),
Type: entryType,
Path: path,
Size: fileInfo.Size(),
Mode: uint32(fileMode.Perm()),
Permissions: fileMode.String(),
Owner: owner,
Group: group,
ModifiedTime: timestamppb.New(fileInfo.ModTime()),
SymlinkTarget: symlinkTarget,
}
}
Loading
Loading