@@ -112,6 +112,46 @@ list_directory_nothrow(std::string const &path)
112112 return ret;
113113}
114114
115+ #ifndef _WIN32
116+ // Need to manually preserve sticky bit and setgid on Unix systems
117+ namespace
118+ {
119+ std::string get_parent (std::string const &path)
120+ {
121+ std::string parent = path;
122+ size_t pos = parent.find_last_of (directory_separator);
123+ if (pos != std::string::npos)
124+ {
125+ parent = parent.substr (0 , pos);
126+ if (parent.empty ())
127+ parent = " /" ;
128+ }
129+ else
130+ {
131+ parent.clear ();
132+ }
133+ return parent;
134+ }
135+
136+ mode_t get_permissions (std::string const &path)
137+ {
138+ std::string parent = get_parent (path);
139+ if (parent.empty () || !directory_exists (parent))
140+ {
141+ return 0 ;
142+ }
143+
144+ struct stat s;
145+ if (stat (parent.c_str (), &s) != 0 )
146+ {
147+ return 0 ;
148+ }
149+
150+ return s.st_mode & 07777 ;
151+ }
152+ } // namespace
153+ #endif
154+
115155bool create_directories (std::string const &path)
116156{
117157 if (directory_exists (path))
@@ -122,10 +162,11 @@ bool create_directories(std::string const &path)
122162 return CreateDirectory (p.c_str (), nullptr );
123163 };
124164#else
125- mode_t mask = umask (0 );
126- umask (mask);
127- auto mk = [mask](std::string const &p) -> bool {
128- return (0 == mkdir (p.c_str (), 0777 & ~mask));
165+ auto mk = [](std::string const &p) -> bool {
166+ // preserve sticky and setgid from parent
167+ mode_t parentPerms =
168+ get_permissions (get_parent (p)) & (S_ISVTX | S_ISGID);
169+ return (0 == mkdir (p.c_str (), 0777 | parentPerms));
129170 };
130171#endif
131172 std::istringstream ss (path);
0 commit comments