60
60
#include <evalfunction.h>
61
61
#include <changes_chroot.h> /* PrepareChangesChroot(), RecordFileChangedInChroot() */
62
62
#include <cf3.defs.h>
63
+ #include <fsattrs.h>
64
+ #include <override_fsattrs.h>
63
65
64
66
static PromiseResult FindFilePromiserObjects (EvalContext * ctx , const Promise * pp );
65
67
static PromiseResult VerifyFilePromise (EvalContext * ctx , char * path , const Promise * pp );
@@ -345,6 +347,67 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi
345
347
changes_path = chrooted_path ;
346
348
}
347
349
350
+ bool is_immutable = false; /* We assume not in case of failure */
351
+ FSAttrsResult res = FSAttrsGetImmutableFlag (changes_path , & is_immutable );
352
+ if (res != FS_ATTRS_SUCCESS )
353
+ {
354
+ Log ((res == FS_ATTRS_FAILURE ) ? LOG_LEVEL_ERR : LOG_LEVEL_VERBOSE ,
355
+ "Failed to get the state of the immutable bit from file '%s': %s" ,
356
+ changes_path , FSAttrsErrorCodeToString (res ));
357
+ }
358
+
359
+ if (a .havefsattrs && a .fsattrs .haveimmutable && !a .fsattrs .immutable )
360
+ {
361
+ /* Here we only handle the clearing of the immutable bit. Later we'll
362
+ * handle the setting of the immutable bit. */
363
+ if (is_immutable )
364
+ {
365
+ res = FSAttrsUpdateImmutableFlag (changes_path , false);
366
+ switch (res )
367
+ {
368
+ case FS_ATTRS_SUCCESS :
369
+ RecordChange (ctx , pp , & a ,
370
+ "Cleared the immutable bit on file '%s'" ,
371
+ changes_path );
372
+ result = PromiseResultUpdate (result , PROMISE_RESULT_CHANGE );
373
+ break ;
374
+ case FS_ATTRS_FAILURE :
375
+ RecordFailure (ctx , pp , & a ,
376
+ "Failed to clear the immutable bit on file '%s'" ,
377
+ changes_path );
378
+ result = PromiseResultUpdate (result , PROMISE_RESULT_FAIL );
379
+ break ;
380
+ case FS_ATTRS_NOT_SUPPORTED :
381
+ /* We will not treat this as a promise failure because this
382
+ * will happen on many platforms and filesystems. Instead we
383
+ * will log a verbose message to make it apparent for the
384
+ * users. */
385
+ Log (LOG_LEVEL_VERBOSE ,
386
+ "Failed to clear the immutable bit on file '%s': %s" ,
387
+ changes_path , FSAttrsErrorCodeToString (res ));
388
+ break ;
389
+ case FS_ATTRS_DOES_NOT_EXIST :
390
+ /* File does not exist. Nothing to do really, but let's log a
391
+ * debug message for good measures */
392
+ Log (LOG_LEVEL_DEBUG ,
393
+ "Failed to clear the immutable bit on file '%s': %s" ,
394
+ changes_path , FSAttrsErrorCodeToString (res ));
395
+ break ;
396
+ }
397
+ }
398
+ else
399
+ {
400
+ RecordNoChange (ctx , pp , & a ,
401
+ "The immutable bit is not set on file '%s' as promised" ,
402
+ changes_path );
403
+ }
404
+ }
405
+
406
+ /* If we encounter any promises to mutate the file and the immutable
407
+ * attribute in body fsattrs is "true", we will override the immutable bit
408
+ * by temporarily clearing it whenever needed. */
409
+ EvalContextOverrideImmutableSet (ctx , a .havefsattrs && a .fsattrs .haveimmutable && a .fsattrs .immutable && is_immutable );
410
+
348
411
if (lstat (changes_path , & oslb ) == -1 ) /* Careful if the object is a link */
349
412
{
350
413
if ((a .create ) || (a .touch ))
@@ -586,6 +649,51 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi
586
649
}
587
650
}
588
651
652
+ if (a .havefsattrs && a .fsattrs .haveimmutable && a .fsattrs .immutable )
653
+ {
654
+ /* Here we only handle the setting of the immutable bit. Previously we
655
+ * handled the clearing of the immutable bit. */
656
+ if (is_immutable )
657
+ {
658
+ RecordNoChange (ctx , pp , & a ,
659
+ "The immutable bit is already set on file '%s' as promised" ,
660
+ changes_path );
661
+ }
662
+ else
663
+ {
664
+ res = FSAttrsUpdateImmutableFlag (changes_path , true);
665
+ switch (res )
666
+ {
667
+ case FS_ATTRS_SUCCESS :
668
+ Log (LOG_LEVEL_VERBOSE , "Set the immutable bit on file '%s'" ,
669
+ changes_path );
670
+ break ;
671
+ case FS_ATTRS_FAILURE :
672
+ /* Things still may be fine as long as the agent does not try to mutate the file */
673
+ Log (LOG_LEVEL_VERBOSE ,
674
+ "Failed to set the immutable bit on file '%s': %s" ,
675
+ changes_path , FSAttrsErrorCodeToString (res ));
676
+ break ;
677
+ case FS_ATTRS_NOT_SUPPORTED :
678
+ /* We will not treat this as a promise failure because this
679
+ * will happen on many platforms and filesystems. Instead we
680
+ * will log a verbose message to make it apparent for the
681
+ * users. */
682
+ Log (LOG_LEVEL_VERBOSE ,
683
+ "Failed to set the immutable bit on file '%s': %s" ,
684
+ changes_path , FSAttrsErrorCodeToString (res ));
685
+ break ;
686
+ case FS_ATTRS_DOES_NOT_EXIST :
687
+ /* File does not exist. Nothing to do really, but let's log a
688
+ * debug message for good measures */
689
+ Log (LOG_LEVEL_DEBUG ,
690
+ "Failed to set the immutable bit on file '%s': %s" ,
691
+ changes_path , FSAttrsErrorCodeToString (res ));
692
+ break ;
693
+ }
694
+ }
695
+ }
696
+
589
697
// Once more in case a file has been created as a result of editing or copying
590
698
591
699
exists = (lstat (changes_path , & osb ) != -1 );
@@ -603,6 +711,9 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi
603
711
}
604
712
605
713
exit :
714
+ /* Reset this to false before next file promise */
715
+ EvalContextOverrideImmutableSet (ctx , false);
716
+
606
717
free (chrooted_path );
607
718
if (AttrHasNoAction (& a ))
608
719
{
@@ -686,20 +797,31 @@ static PromiseResult WriteContentFromString(EvalContext *ctx, const char *path,
686
797
687
798
if (!HashesMatch (existing_content_digest , promised_content_digest , CF_DEFAULT_DIGEST ))
688
799
{
800
+ bool override_immutable = EvalContextOverrideImmutableGet (ctx );
689
801
if (!MakingChanges (ctx , pp , attr , & result ,
690
802
"update file '%s' with content '%s'" ,
691
803
path , attr -> content ))
692
804
{
693
805
return result ;
694
806
}
695
807
696
- FILE * f = safe_fopen (changes_path , "w" );
808
+ char override_path [PATH_MAX ];
809
+ if (!OverrideImmutableBegin (changes_path , override_path , sizeof (override_path ), override_immutable ))
810
+ {
811
+ RecordFailure (ctx , pp , attr , "Failed to override immutable bit on file '%s'" , changes_path );
812
+ return PromiseResultUpdate (result , PROMISE_RESULT_FAIL );
813
+ }
814
+
815
+ FILE * f = safe_fopen (override_path , "w" );
697
816
if (f == NULL )
698
817
{
699
818
RecordFailure (ctx , pp , attr , "Cannot open file '%s' for writing" , path );
819
+ OverrideImmutableCommit (changes_path , override_path , override_immutable , true);
700
820
return PromiseResultUpdate (result , PROMISE_RESULT_FAIL );
701
821
}
702
822
823
+ bool override_abort = false;
824
+
703
825
Writer * w = FileWriter (f );
704
826
if (WriterWriteLen (w , attr -> content , bytes_to_write ) == bytes_to_write )
705
827
{
@@ -714,9 +836,16 @@ static PromiseResult WriteContentFromString(EvalContext *ctx, const char *path,
714
836
RecordFailure (ctx , pp , attr ,
715
837
"Failed to update file '%s' with content '%s'" ,
716
838
path , attr -> content );
839
+ override_abort = true;
717
840
result = PromiseResultUpdate (result , PROMISE_RESULT_FAIL );
718
841
}
719
842
WriterClose (w );
843
+
844
+ if (!OverrideImmutableCommit (changes_path , override_path , override_immutable , override_abort ))
845
+ {
846
+ RecordFailure (ctx , pp , attr , "Failed to override immutable bit on file '%s'" , changes_path );
847
+ result = PromiseResultUpdate (result , PROMISE_RESULT_FAIL );
848
+ }
720
849
}
721
850
722
851
return result ;
@@ -861,7 +990,7 @@ static PromiseResult RenderTemplateMustache(EvalContext *ctx,
861
990
edcontext -> filename , message );
862
991
result = PromiseResultUpdate (result , PROMISE_RESULT_FAIL );
863
992
}
864
- else if (SaveAsFile (SaveBufferCallback , output_buffer ,
993
+ else if (SaveAsFile (ctx , SaveBufferCallback , output_buffer ,
865
994
edcontext -> changes_filename , attr ,
866
995
edcontext -> new_line_mode ))
867
996
{
0 commit comments