@@ -10,6 +10,7 @@ import (
1010 "net/http"
1111 "net/url"
1212 "os"
13+ "path"
1314 "path/filepath"
1415 "strings"
1516 "syscall"
@@ -185,12 +186,13 @@ func CpToInstance(ctx context.Context, cfg CpConfig, opts CpToInstanceOptions) e
185186
186187 // Send initial request
187188 req := cpRequest {
188- Direction : "to" ,
189- GuestPath : opts .DstPath ,
190- IsDir : srcInfo .IsDir (),
191- Mode : uint32 (mode ),
192- Uid : uid ,
193- Gid : gid ,
189+ Direction : "to" ,
190+ GuestPath : opts .DstPath ,
191+ IsDir : srcInfo .IsDir (),
192+ Mode : uint32 (mode ),
193+ FollowLinks : opts .FollowLinks ,
194+ Uid : uid ,
195+ Gid : gid ,
194196 }
195197 reqJSON , _ := json .Marshal (req )
196198 if err := ws .WriteMessage (websocket .TextMessage , reqJSON ); err != nil {
@@ -292,21 +294,23 @@ func copyDirToWs(ctx context.Context, cfg CpConfig, ws WsConn, srcPath, dstPath,
292294 }
293295
294296 // Now recursively copy contents
295- return filepath .WalkDir (srcPath , func (path string , d fs.DirEntry , err error ) error {
297+ return filepath .WalkDir (srcPath , func (walkPath string , d fs.DirEntry , err error ) error {
296298 if err != nil {
297299 return err
298300 }
299301
300- if path == srcPath {
302+ if walkPath == srcPath {
301303 return nil // Skip root
302304 }
303305
304- relPath , err := filepath .Rel (srcPath , path )
306+ relPath , err := filepath .Rel (srcPath , walkPath )
305307 if err != nil {
306308 return fmt .Errorf ("relative path: %w" , err )
307309 }
308310
309- targetPath := filepath .Join (dstPath , relPath )
311+ // Use path.Join (not filepath.Join) for guest paths to ensure forward slashes
312+ // Convert Windows backslashes to forward slashes for Linux guest
313+ targetPath := path .Join (dstPath , filepath .ToSlash (relPath ))
310314 info , err := d .Info ()
311315 if err != nil {
312316 return fmt .Errorf ("info: %w" , err )
@@ -316,7 +320,7 @@ func copyDirToWs(ctx context.Context, cfg CpConfig, ws WsConn, srcPath, dstPath,
316320 // This is because the protocol is one-file-per-connection
317321 return CpToInstance (ctx , cfg , CpToInstanceOptions {
318322 InstanceID : instanceID ,
319- SrcPath : path ,
323+ SrcPath : walkPath ,
320324 DstPath : targetPath ,
321325 Mode : info .Mode ().Perm (),
322326 Callbacks : callbacks ,
0 commit comments