@@ -9,6 +9,7 @@ in the source distribution for its full text.
99
1010#include "Settings.h"
1111
12+ #include <assert.h>
1213#include <ctype.h>
1314#include <errno.h>
1415#include <fcntl.h>
@@ -563,6 +564,51 @@ static bool Settings_read(Settings* this, const char* fileName, const Machine* h
563564 return didReadAny ;
564565}
565566
567+ static int makeAncestorDirectories (char * filePath , size_t len ) {
568+ assert (len == strlen (filePath ));
569+
570+ // The caller is expected to set the umask before calling this function.
571+ // In particular, if the umask contains S_IWUSR or S_IXUSR bit then the
572+ // making of subdirectories within the ancestor can fail.
573+
574+ int ret = 0 ;
575+ int savedErr = errno ;
576+
577+ char * p = filePath + len ;
578+ for (; p > filePath ; p -- ) {
579+ if (* p != '/' )
580+ continue ;
581+
582+ * p = '\0' ;
583+ bool ok = !mkdir (filePath , S_IRWXU );
584+ * p = '/' ;
585+ if (ok )
586+ break ;
587+
588+ if (errno != ENOENT )
589+ return - errno ;
590+
591+ ret = - errno ;
592+ }
593+ if (p <= filePath )
594+ return ret ;
595+
596+ errno = savedErr ;
597+
598+ while (++ p < filePath + len ) {
599+ assert (* p );
600+ if (* p != '/' )
601+ continue ;
602+
603+ * p = '\0' ;
604+ bool ok = !mkdir (filePath , S_IRWXU );
605+ * p = '/' ;
606+ if (!ok )
607+ return - errno ;
608+ }
609+ return 0 ;
610+ }
611+
566612typedef ATTR_FORMAT (printf , 2 , 3 ) int (* OutputFunc )(FILE * , const char * ,...);
567613
568614static void writeFields (OutputFunc of , FILE * fp ,
@@ -649,9 +695,15 @@ int Settings_write(const Settings* this, bool onCrash) {
649695 } else if (!this -> writeConfig ) {
650696 return 0 ;
651697 } else {
652- /* create tempfile with mode 0600 */
653- mode_t cur_umask = umask (S_IXUSR | S_IRWXG | S_IRWXO );
654- xAsprintf (& tmpFilename , "%s.tmp.XXXXXX" , this -> filename );
698+ // Prepare temp filename
699+ size_t nameLen = (size_t )xAsprintf (& tmpFilename , "%s.tmp.XXXXXX" , this -> filename );
700+
701+ // Create ancestor directories with mode 0700
702+ mode_t cur_umask = umask (S_IRWXG | S_IRWXO );
703+ makeAncestorDirectories (tmpFilename , nameLen );
704+
705+ // Create temp file with mode 0600
706+ umask (S_IXUSR | S_IRWXG | S_IRWXO );
655707 int fdtmp = mkstemp (tmpFilename );
656708 umask (cur_umask );
657709 if (fdtmp == -1 ) {
@@ -851,8 +903,6 @@ Settings* Settings_new(const Machine* host, Hashtable* dynamicMeters, Hashtable*
851903 configDir = String_cat (home , CONFIGDIR );
852904 htopDir = String_cat (home , CONFIGDIR "/htop" );
853905 }
854- (void ) mkdir (configDir , 0700 );
855- (void ) mkdir (htopDir , 0700 );
856906 free (htopDir );
857907 free (configDir );
858908
0 commit comments