@@ -859,7 +859,7 @@ func copyFromInstanceToStdout(ctx context.Context, baseURL, apiKey, instanceID,
859859 defer tw .Close ()
860860
861861 var currentHeader * cpFileHeader
862- var fileData [] byte
862+ var bytesWritten int64
863863 var receivedFinal bool
864864
865865 for {
@@ -881,19 +881,19 @@ func copyFromInstanceToStdout(ctx context.Context, baseURL, apiKey, instanceID,
881881
882882 switch msgTypeStr {
883883 case "header" :
884- // Flush previous file if any (but not symlinks - they have no data)
884+ // Verify previous file was completely written
885885 if currentHeader != nil && ! currentHeader .IsDir && ! currentHeader .IsSymlink {
886- if err := writeTarEntry ( tw , currentHeader , fileData , archive ); err != nil {
887- return err
886+ if bytesWritten != currentHeader . Size {
887+ return fmt . Errorf ( "file %s: expected %d bytes, got %d" , currentHeader . Path , currentHeader . Size , bytesWritten )
888888 }
889- fileData = nil
890889 }
891890
892891 var header cpFileHeader
893892 if err := json .Unmarshal (message , & header ); err != nil {
894893 return fmt .Errorf ("parse header: %w" , err )
895894 }
896895 currentHeader = & header
896+ bytesWritten = 0
897897
898898 if header .IsDir {
899899 // Write directory entry to tar
@@ -928,15 +928,31 @@ func copyFromInstanceToStdout(ctx context.Context, baseURL, apiKey, instanceID,
928928 if err := tw .WriteHeader (tarHeader ); err != nil {
929929 return fmt .Errorf ("write tar symlink header: %w" , err )
930930 }
931+ } else {
932+ // Write regular file header with known size - enables streaming
933+ tarHeader := & tar.Header {
934+ Typeflag : tar .TypeReg ,
935+ Name : header .Path ,
936+ Size : header .Size ,
937+ Mode : int64 (header .Mode ),
938+ ModTime : time .Unix (header .Mtime , 0 ),
939+ }
940+ // Only preserve UID/GID in archive mode
941+ if archive {
942+ tarHeader .Uid = int (header .Uid )
943+ tarHeader .Gid = int (header .Gid )
944+ }
945+ if err := tw .WriteHeader (tarHeader ); err != nil {
946+ return fmt .Errorf ("write tar header: %w" , err )
947+ }
931948 }
932949
933950 case "end" :
934- // Write final file data if any
951+ // Verify file was completely written
935952 if currentHeader != nil && ! currentHeader .IsDir && ! currentHeader .IsSymlink {
936- if err := writeTarEntry ( tw , currentHeader , fileData , archive ); err != nil {
937- return err
953+ if bytesWritten != currentHeader . Size {
954+ return fmt . Errorf ( "file %s: expected %d bytes, got %d" , currentHeader . Path , currentHeader . Size , bytesWritten )
938955 }
939- fileData = nil
940956 }
941957 currentHeader = nil
942958
@@ -953,8 +969,12 @@ func copyFromInstanceToStdout(ctx context.Context, baseURL, apiKey, instanceID,
953969 return fmt .Errorf ("copy error at %s: %s" , cpErr .Path , cpErr .Message )
954970 }
955971 } else if msgType == websocket .BinaryMessage {
956- // Accumulate file data
957- fileData = append (fileData , message ... )
972+ // Stream file data directly to tar archive
973+ n , err := tw .Write (message )
974+ if err != nil {
975+ return fmt .Errorf ("write tar data: %w" , err )
976+ }
977+ bytesWritten += int64 (n )
958978 }
959979 }
960980
@@ -965,26 +985,4 @@ func copyFromInstanceToStdout(ctx context.Context, baseURL, apiKey, instanceID,
965985 return nil
966986}
967987
968- // writeTarEntry writes a file entry to the tar archive
969- func writeTarEntry (tw * tar.Writer , header * cpFileHeader , data []byte , archive bool ) error {
970- tarHeader := & tar.Header {
971- Typeflag : tar .TypeReg ,
972- Name : header .Path ,
973- Size : int64 (len (data )),
974- Mode : int64 (header .Mode ),
975- ModTime : time .Unix (header .Mtime , 0 ),
976- }
977- // Only preserve UID/GID in archive mode
978- if archive {
979- tarHeader .Uid = int (header .Uid )
980- tarHeader .Gid = int (header .Gid )
981- }
982- if err := tw .WriteHeader (tarHeader ); err != nil {
983- return fmt .Errorf ("write tar header: %w" , err )
984- }
985- if _ , err := tw .Write (data ); err != nil {
986- return fmt .Errorf ("write tar data: %w" , err )
987- }
988- return nil
989- }
990988
0 commit comments