@@ -40,7 +40,6 @@ import (
4040 "golang.org/x/text/transform"
4141
4242 "github.com/1Panel-dev/1Panel/agent/global"
43- "github.com/1Panel-dev/1Panel/agent/utils/cmd"
4443 "github.com/1Panel-dev/1Panel/agent/utils/common"
4544 "github.com/1Panel-dev/1Panel/agent/utils/files"
4645 terminalai "github.com/1Panel-dev/1Panel/agent/utils/terminal/ai"
@@ -478,7 +477,7 @@ func preflightCompressTool(compressType files.CompressType) error {
478477
479478func preflightDecompressTool (decompressType files.CompressType ) error {
480479 switch decompressType {
481- case files .Tar , files . Zip , files . TarGz , files . Rar , files .X7z :
480+ case files .Rar , files .X7z :
482481 _ , err := files .NewExtractShellArchiver (decompressType )
483482 return err
484483 default :
@@ -541,7 +540,7 @@ func (f *FileService) DeCompress(c request.FileDeCompress) error {
541540 if err := fo .CreateDir (c .Dst , constant .DirPerm ); err != nil {
542541 return err
543542 }
544- if err := cmd . NewCommandMgr ( cmd . WithContext ( t .TaskCtx )). RunBashCf ( "cp -rfp '%s'/. '%s'" , tempDst , c .Dst ); err != nil {
543+ if err := copyDecompressTree ( t .TaskCtx , tempDst , c .Dst ); err != nil {
545544 return err
546545 }
547546 success = true
@@ -552,6 +551,124 @@ func (f *FileService) DeCompress(c request.FileDeCompress) error {
552551 return nil
553552}
554553
554+ func copyDecompressTree (ctx context.Context , srcDir , dstDir string ) error {
555+ entries , err := os .ReadDir (srcDir )
556+ if err != nil {
557+ return err
558+ }
559+ for _ , entry := range entries {
560+ if err := copyDecompressEntry (ctx , filepath .Join (srcDir , entry .Name ()), filepath .Join (dstDir , entry .Name ())); err != nil {
561+ return err
562+ }
563+ }
564+ return nil
565+ }
566+
567+ func copyDecompressEntry (ctx context.Context , srcPath , dstPath string ) (retErr error ) {
568+ if err := ctx .Err (); err != nil {
569+ return err
570+ }
571+ info , err := os .Lstat (srcPath )
572+ if err != nil {
573+ return err
574+ }
575+
576+ if info .Mode ()& os .ModeSymlink != 0 {
577+ if err := os .RemoveAll (dstPath ); err != nil {
578+ return err
579+ }
580+ if err := os .MkdirAll (filepath .Dir (dstPath ), constant .DirPerm ); err != nil {
581+ return err
582+ }
583+ target , err := os .Readlink (srcPath )
584+ if err != nil {
585+ return err
586+ }
587+ if err := os .Symlink (target , dstPath ); err != nil {
588+ return err
589+ }
590+ return applyDecompressOwnership (srcPath , dstPath )
591+ }
592+
593+ if info .IsDir () {
594+ dstInfo , err := os .Lstat (dstPath )
595+ keepExistingDir := err == nil && dstInfo .IsDir () && dstInfo .Mode ()& os .ModeSymlink == 0
596+ if err != nil && ! os .IsNotExist (err ) {
597+ return err
598+ }
599+ if ! keepExistingDir {
600+ if err := os .RemoveAll (dstPath ); err != nil {
601+ return err
602+ }
603+ if err := os .MkdirAll (dstPath , info .Mode ().Perm ()); err != nil {
604+ return err
605+ }
606+ if err := applyDecompressOwnership (srcPath , dstPath ); err != nil {
607+ return err
608+ }
609+ }
610+ entries , err := os .ReadDir (srcPath )
611+ if err != nil {
612+ return err
613+ }
614+ for _ , entry := range entries {
615+ if err := copyDecompressEntry (ctx , filepath .Join (srcPath , entry .Name ()), filepath .Join (dstPath , entry .Name ())); err != nil {
616+ return err
617+ }
618+ }
619+ if keepExistingDir {
620+ return nil
621+ }
622+ return os .Chtimes (dstPath , info .ModTime (), info .ModTime ())
623+ }
624+
625+ if err := os .RemoveAll (dstPath ); err != nil {
626+ return err
627+ }
628+ if err := os .MkdirAll (filepath .Dir (dstPath ), constant .DirPerm ); err != nil {
629+ return err
630+ }
631+
632+ srcFile , err := os .Open (srcPath )
633+ if err != nil {
634+ return err
635+ }
636+ defer srcFile .Close ()
637+
638+ dstFile , err := os .OpenFile (dstPath , os .O_CREATE | os .O_RDWR | os .O_TRUNC , info .Mode ().Perm ())
639+ if err != nil {
640+ return err
641+ }
642+ defer func () {
643+ if cerr := dstFile .Close (); cerr != nil && retErr == nil {
644+ retErr = cerr
645+ }
646+ }()
647+
648+ if _ , err := io .Copy (dstFile , srcFile ); err != nil {
649+ return err
650+ }
651+ if err := applyDecompressOwnership (srcPath , dstPath ); err != nil {
652+ return err
653+ }
654+ return os .Chtimes (dstPath , info .ModTime (), info .ModTime ())
655+ }
656+
657+ func applyDecompressOwnership (srcPath , dstPath string ) error {
658+ info , err := os .Lstat (srcPath )
659+ if err != nil {
660+ return err
661+ }
662+ stat , ok := info .Sys ().(* unix.Stat_t )
663+ if ! ok {
664+ return nil
665+ }
666+ if info .Mode ()& os .ModeSymlink != 0 {
667+ return os .Lchown (dstPath , int (stat .Uid ), int (stat .Gid ))
668+ }
669+ return os .Chown (dstPath , int (stat .Uid ), int (stat .Gid ))
670+ }
671+
555672func (f * FileService ) GetContent (op request.FileContentReq ) (response.FileInfo , error ) {
556673 info , err := files .NewFileInfo (files.FileOption {
557674 Path : op .Path ,
0 commit comments