@@ -563,6 +563,43 @@ static bool Settings_read(Settings* this, const char* fileName, const Machine* h
563563 return didReadAny ;
564564}
565565
566+ static int makeAncestorDirectories (char * filePath ) {
567+ // The caller is expected to set the umask before calling this function.
568+ // In particular, if the umask contains S_IWUSR or S_IXUSR bit then the
569+ // making of subdirectories within the ancestor can fail.
570+
571+ // 0755 is the maximum permission we can give to directories at this phase.
572+ const mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ;
573+
574+ bool hasDirectory = false;
575+ int savedErr = errno ;
576+
577+ char * p = filePath ;
578+ while (true) {
579+ while (* p == '/' )
580+ p ++ ;
581+
582+ while (* p && * p != '/' )
583+ p ++ ;
584+
585+ if (!* p )
586+ break ;
587+
588+ * p = '\0' ;
589+ bool ok = !mkdir (filePath , mode );
590+ * p = '/' ;
591+ if (ok ) {
592+ hasDirectory = true;
593+ errno = savedErr ;
594+ } else if (hasDirectory ) {
595+ return - errno ;
596+ }
597+ // Try creating directories in the lower levels. It's possible for
598+ // mkdir() to succeed in a lower level while an error happens earlier.
599+ }
600+ return 0 ;
601+ }
602+
566603typedef ATTR_FORMAT (printf , 2 , 3 ) int (* OutputFunc )(FILE * , const char * ,...);
567604
568605static void writeFields (OutputFunc of , FILE * fp ,
@@ -649,9 +686,15 @@ int Settings_write(const Settings* this, bool onCrash) {
649686 } else if (!this -> writeConfig ) {
650687 return 0 ;
651688 } else {
652- /* create tempfile with mode 0600 */
653- mode_t cur_umask = umask (S_IXUSR | S_IRWXG | S_IRWXO );
689+ // Prepare temp filename
654690 xAsprintf (& tmpFilename , "%s.tmp.XXXXXX" , this -> filename );
691+
692+ // Create ancestor directories with mode 0700
693+ mode_t cur_umask = umask (S_IRWXG | S_IRWXO );
694+ makeAncestorDirectories (tmpFilename );
695+
696+ // Create temp file with mode 0600
697+ umask (S_IXUSR | S_IRWXG | S_IRWXO );
655698 int fdtmp = mkstemp (tmpFilename );
656699 umask (cur_umask );
657700 if (fdtmp == -1 ) {
@@ -851,8 +894,6 @@ Settings* Settings_new(const Machine* host, Hashtable* dynamicMeters, Hashtable*
851894 configDir = String_cat (home , CONFIGDIR );
852895 htopDir = String_cat (home , CONFIGDIR "/htop" );
853896 }
854- (void ) mkdir (configDir , 0700 );
855- (void ) mkdir (htopDir , 0700 );
856897 free (htopDir );
857898 free (configDir );
858899
0 commit comments