@@ -13,6 +13,7 @@ import (
1313 "fmt"
1414 "log/slog"
1515 "os"
16+ "path/filepath"
1617 "sync"
1718
1819 "google.golang.org/grpc"
@@ -38,11 +39,11 @@ const (
3839
3940type (
4041 fileOperator interface {
41- Write (ctx context.Context , fileContent []byte , file * mpi. FileMeta ) error
42- CreateFileDirectories (ctx context.Context , fileMeta * mpi. FileMeta , filePermission os. FileMode ) error
42+ Write (ctx context.Context , fileContent []byte , fileName , filePermissions string ) error
43+ CreateFileDirectories (ctx context.Context , fileName string ) error
4344 WriteChunkedFile (
4445 ctx context.Context ,
45- file * mpi. File ,
46+ fileName , filePermissions string ,
4647 header * mpi.FileDataChunkHeader ,
4748 stream grpc.ServerStreamingClient [mpi.FileDataChunk ],
4849 ) error
@@ -57,17 +58,18 @@ type (
5758 }
5859
5960 fileServiceOperatorInterface interface {
60- File (ctx context.Context , file * mpi.File , fileActions map [ string ] * model. FileCache ) error
61+ File (ctx context.Context , file * mpi.File , tempFilePath , expectedHash string ) error
6162 UpdateOverview (ctx context.Context , instanceID string , filesToUpdate []* mpi.File , configPath string ,
6263 iteration int ) error
63- ChunkedFile (ctx context.Context , file * mpi.File ) error
64+ ChunkedFile (ctx context.Context , file * mpi.File , tempFilePath , expectedHash string ) error
6465 IsConnected () bool
6566 UpdateFile (
6667 ctx context.Context ,
6768 instanceID string ,
6869 fileToUpdate * mpi.File ,
6970 ) error
7071 SetIsConnected (isConnected bool )
72+ ValidateFileHash (filePath , expectedHash string ) error
7173 }
7274
7375 fileManagerServiceInterface interface {
@@ -196,15 +198,16 @@ func (fms *FileManagerService) Rollback(ctx context.Context, instanceID string)
196198
197199 continue
198200 case model .Delete , model .Update :
199- content := fms .rollbackFileContents [fileAction .File .GetFileMeta ().GetName ()]
200- err := fms .fileOperator .Write (ctx , content , fileAction .File .GetFileMeta ())
201+ fileMeta := fileAction .File .GetFileMeta ()
202+ content := fms .rollbackFileContents [fileMeta .GetName ()]
203+ err := fms .fileOperator .Write (ctx , content , fileMeta .GetName (), fileMeta .GetPermissions ())
201204 if err != nil {
202205 return err
203206 }
204207
205208 // currentFilesOnDisk needs to be updated after rollback action is performed
206- fileAction . File . GetFileMeta () .Hash = files .GenerateHash (content )
207- fms .currentFilesOnDisk [fileAction . File . GetFileMeta () .GetName ()] = fileAction .File
209+ fileMeta .Hash = files .GenerateHash (content )
210+ fms .currentFilesOnDisk [fileMeta .GetName ()] = fileAction .File
208211 case model .Unchanged :
209212 fallthrough
210213 default :
@@ -448,21 +451,29 @@ func (fms *FileManagerService) manifestFile() (map[string]*model.ManifestFile, m
448451}
449452
450453func (fms * FileManagerService ) executeFileActions (ctx context.Context ) error {
454+ tempDir := os .TempDir ()
455+
456+ // Download files to temporary location
457+ downloadError := fms .downloadUpdatedFilesToTempLocation (ctx , tempDir )
458+ if downloadError != nil {
459+ return downloadError
460+ }
461+
462+ // Move/Delete files
451463 for _ , fileAction := range fms .fileActions {
452464 switch fileAction .Action {
453465 case model .Delete :
454- slog .DebugContext (ctx , "File action, deleting file" , "file" , fileAction .File .GetFileMeta ().GetName ())
466+ slog .DebugContext (ctx , "Deleting file" , "file" , fileAction .File .GetFileMeta ().GetName ())
455467 if err := os .Remove (fileAction .File .GetFileMeta ().GetName ()); err != nil && ! os .IsNotExist (err ) {
456468 return fmt .Errorf ("error deleting file: %s error: %w" ,
457469 fileAction .File .GetFileMeta ().GetName (), err )
458470 }
459471
460472 continue
461473 case model .Add , model .Update :
462- slog .DebugContext (ctx , "File action, add or update file" , "file" , fileAction .File .GetFileMeta ().GetName ())
463- updateErr := fms .fileUpdate (ctx , fileAction .File )
464- if updateErr != nil {
465- return updateErr
474+ err := fms .moveFilesFromTempDirectory (ctx , fileAction , tempDir )
475+ if err != nil {
476+ return err
466477 }
467478 case model .Unchanged :
468479 slog .DebugContext (ctx , "File unchanged" )
@@ -472,12 +483,64 @@ func (fms *FileManagerService) executeFileActions(ctx context.Context) error {
472483 return nil
473484}
474485
475- func (fms * FileManagerService ) fileUpdate (ctx context.Context , file * mpi.File ) error {
486+ func (fms * FileManagerService ) moveFilesFromTempDirectory (
487+ ctx context.Context , fileAction * model.FileCache , tempDir string ,
488+ ) error {
489+ fileName := fileAction .File .GetFileMeta ().GetName ()
490+ slog .DebugContext (ctx , "Updating file" , "file" , fileName )
491+ tempFilePath := filepath .Join (tempDir , fileName )
492+
493+ // Create parent directories for the target file if they don't exist
494+ if err := os .MkdirAll (filepath .Dir (fileName ), dirPerm ); err != nil {
495+ return fmt .Errorf ("failed to create directories for %s: %w" , fileName , err )
496+ }
497+
498+ moveErr := os .Rename (tempFilePath , fileName )
499+ if moveErr != nil {
500+ return fmt .Errorf ("failed to rename file: %w" , moveErr )
501+ }
502+
503+ if removeError := os .Remove (tempFilePath ); removeError != nil && ! os .IsNotExist (removeError ) {
504+ slog .ErrorContext (
505+ ctx ,
506+ "Error deleting temp file" ,
507+ "file" , fileName ,
508+ "error" , removeError ,
509+ )
510+ }
511+
512+ return fms .fileServiceOperator .ValidateFileHash (fileName , fileAction .File .GetFileMeta ().GetHash ())
513+ }
514+
515+ func (fms * FileManagerService ) downloadUpdatedFilesToTempLocation (ctx context.Context , tempDir string ) error {
516+ for _ , fileAction := range fms .fileActions {
517+ if fileAction .Action == model .Add || fileAction .Action == model .Update {
518+ tempFilePath := filepath .Join (tempDir , fileAction .File .GetFileMeta ().GetName ())
519+
520+ slog .DebugContext (
521+ ctx ,
522+ "Downloading file to temp location" ,
523+ "file" , tempFilePath ,
524+ )
525+
526+ updateErr := fms .fileUpdate (ctx , fileAction .File , tempFilePath )
527+ if updateErr != nil {
528+ return updateErr
529+ }
530+ }
531+ }
532+
533+ return nil
534+ }
535+
536+ func (fms * FileManagerService ) fileUpdate (ctx context.Context , file * mpi.File , tempFilePath string ) error {
537+ expectedHash := fms .fileActions [file .GetFileMeta ().GetName ()].File .GetFileMeta ().GetHash ()
538+
476539 if file .GetFileMeta ().GetSize () <= int64 (fms .agentConfig .Client .Grpc .MaxFileSize ) {
477- return fms .fileServiceOperator .File (ctx , file , fms . fileActions )
540+ return fms .fileServiceOperator .File (ctx , file , tempFilePath , expectedHash )
478541 }
479542
480- return fms .fileServiceOperator .ChunkedFile (ctx , file )
543+ return fms .fileServiceOperator .ChunkedFile (ctx , file , tempFilePath , expectedHash )
481544}
482545
483546func (fms * FileManagerService ) checkAllowedDirectory (checkFiles []* mpi.File ) error {
0 commit comments