Skip to content

Commit 69443ce

Browse files
committed
windows multi-drive, add absolutepath
1 parent 163a149 commit 69443ce

File tree

3 files changed

+80
-25
lines changed

3 files changed

+80
-25
lines changed

agent/ls.go

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import (
66
"os"
77
"path/filepath"
88
"runtime"
9+
"strings"
910

11+
"github.com/shirou/gopsutil/v3/disk"
1012
"golang.org/x/xerrors"
1113

1214
"github.com/coder/coder/v2/coderd/httpapi"
@@ -26,11 +28,11 @@ func (*agent) HandleLS(rw http.ResponseWriter, r *http.Request) {
2628
switch {
2729
case errors.Is(err, os.ErrNotExist):
2830
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
29-
Message: "Directory does not exist",
31+
Message: err.Error(),
3032
})
3133
case errors.Is(err, os.ErrPermission):
3234
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
33-
Message: "Permission denied",
35+
Message: err.Error(),
3436
})
3537
default:
3638
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
@@ -44,28 +46,27 @@ func (*agent) HandleLS(rw http.ResponseWriter, r *http.Request) {
4446
}
4547

4648
func listFiles(query LSQuery) (LSResponse, error) {
47-
var base string
49+
var fullPath []string
4850
switch query.Relativity {
4951
case LSRelativityHome:
5052
home, err := os.UserHomeDir()
5153
if err != nil {
5254
return LSResponse{}, xerrors.Errorf("failed to get user home directory: %w", err)
5355
}
54-
base = home
56+
fullPath = []string{home}
5557
case LSRelativityRoot:
5658
if runtime.GOOS == "windows" {
57-
// TODO: Eventually, we could have a empty path with a root base
58-
// return all drives.
59-
// C drive should be good enough for now.
60-
base = "C:\\"
59+
if len(query.Path) == 0 {
60+
return listDrives()
61+
}
6162
} else {
62-
base = "/"
63+
fullPath = []string{"/"}
6364
}
6465
default:
6566
return LSResponse{}, xerrors.Errorf("unsupported relativity type %q", query.Relativity)
6667
}
6768

68-
fullPath := append([]string{base}, query.Path...)
69+
fullPath = append(fullPath, query.Path...)
6970
absolutePathString, err := filepath.Abs(filepath.Join(fullPath...))
7071
if err != nil {
7172
return LSResponse{}, xerrors.Errorf("failed to get absolute path: %w", err)
@@ -97,12 +98,48 @@ func listFiles(query LSQuery) (LSResponse, error) {
9798
})
9899
}
99100

101+
absolutePath := pathToArray(absolutePathString)
102+
100103
return LSResponse{
104+
AbsolutePath: absolutePath,
101105
AbsolutePathString: absolutePathString,
102106
Contents: respContents,
103107
}, nil
104108
}
105109

110+
func listDrives() (LSResponse, error) {
111+
aa, err := disk.Partitions(true)
112+
if err != nil {
113+
return LSResponse{}, xerrors.Errorf("failed to get partitions: %w", err)
114+
}
115+
contents := make([]LSFile, 0, len(aa))
116+
for _, a := range aa {
117+
name := a.Mountpoint + string(os.PathSeparator)
118+
contents = append(contents, LSFile{
119+
Name: name,
120+
AbsolutePathString: name,
121+
IsDir: true,
122+
})
123+
}
124+
125+
return LSResponse{
126+
AbsolutePath: []string{},
127+
AbsolutePathString: "",
128+
Contents: contents,
129+
}, nil
130+
}
131+
132+
func pathToArray(path string) []string {
133+
out := strings.FieldsFunc(path, func(r rune) bool {
134+
return r == os.PathSeparator
135+
})
136+
// Drive letters on Windows should have a trailing separator.
137+
if runtime.GOOS == "windows" && len(out) > 0 {
138+
out[0] += string(os.PathSeparator)
139+
}
140+
return out
141+
}
142+
106143
type LSQuery struct {
107144
// e.g. [], ["repos", "coder"],
108145
Path []string `json:"path"`
@@ -112,6 +149,7 @@ type LSQuery struct {
112149
}
113150

114151
type LSResponse struct {
152+
AbsolutePath []string `json:"absolute_path"`
115153
// Returned so clients can display the full path to the user, and
116154
// copy it to configure file sync
117155
// e.g. Windows: "C:\\Users\\coder"

agent/ls_internal_test.go

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"os"
55
"path/filepath"
66
"runtime"
7-
"strings"
87
"testing"
98

109
"github.com/stretchr/testify/require"
@@ -90,9 +89,9 @@ func TestListFilesSuccess(t *testing.T) {
9089
},
9190
{
9291
name: "root",
93-
baseFunc: func(t *testing.T) string {
92+
baseFunc: func(*testing.T) string {
9493
if runtime.GOOS == "windows" {
95-
return "C:\\"
94+
return ""
9695
}
9796
return "/"
9897
},
@@ -116,12 +115,18 @@ func TestListFilesSuccess(t *testing.T) {
116115
err = os.Mkdir(downloadsDir, 0o755)
117116
require.NoError(t, err)
118117

119-
rel, err := filepath.Rel(base, tmpDir)
120-
require.NoError(t, err)
121-
relComponents := pathToArray(rel)
118+
var queryComponents []string
119+
// We can't get an absolute path relative to empty string on Windows.
120+
if runtime.GOOS == "windows" && base == "" {
121+
queryComponents = pathToArray(tmpDir)
122+
} else {
123+
rel, err := filepath.Rel(base, tmpDir)
124+
require.NoError(t, err)
125+
queryComponents = pathToArray(rel)
126+
}
122127

123128
query := LSQuery{
124-
Path: relComponents,
129+
Path: queryComponents,
125130
Relativity: tc.relativity,
126131
}
127132
resp, err := listFiles(query)
@@ -149,7 +154,7 @@ func TestListFilesSuccess(t *testing.T) {
149154
}
150155
}
151156

152-
func TestListFilesWindowsRoot(t *testing.T) {
157+
func TestListFilesListDrives(t *testing.T) {
153158
t.Parallel()
154159

155160
if runtime.GOOS != "windows" {
@@ -162,11 +167,23 @@ func TestListFilesWindowsRoot(t *testing.T) {
162167
}
163168
resp, err := listFiles(query)
164169
require.NoError(t, err)
165-
require.Equal(t, "C:\\", resp.AbsolutePathString)
166-
}
167-
168-
func pathToArray(path string) []string {
169-
return strings.FieldsFunc(path, func(r rune) bool {
170-
return r == os.PathSeparator
170+
require.Contains(t, resp.Contents, LSFile{
171+
Name: "C:\\",
172+
AbsolutePathString: "C:\\",
173+
IsDir: true,
171174
})
175+
176+
query = LSQuery{
177+
Path: []string{"C:\\"},
178+
Relativity: LSRelativityRoot,
179+
}
180+
resp, err = listFiles(query)
181+
require.NoError(t, err)
182+
183+
query = LSQuery{
184+
Path: resp.AbsolutePath,
185+
Relativity: LSRelativityRoot,
186+
}
187+
resp, err = listFiles(query)
188+
require.NoError(t, err)
172189
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ require (
401401
github.com/ryanuber/go-glob v1.0.0 // indirect
402402
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
403403
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
404-
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
404+
github.com/shirou/gopsutil/v3 v3.24.4
405405
github.com/shoenig/go-m1cpu v0.1.6 // indirect
406406
github.com/sirupsen/logrus v1.9.3 // indirect
407407
github.com/spaolacci/murmur3 v1.1.0 // indirect

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy