@@ -286,13 +286,58 @@ int mingw_rmdir(const char *pathname)
286286 return ret ;
287287}
288288
289+ static inline int needs_hiding (const char * path )
290+ {
291+ const char * basename ;
292+
293+ if (hide_dotfiles == HIDE_DOTFILES_FALSE )
294+ return 0 ;
295+
296+ /* We cannot use basename(), as it would remove trailing slashes */
297+ mingw_skip_dos_drive_prefix ((char * * )& path );
298+ if (!* path )
299+ return 0 ;
300+
301+ for (basename = path ; * path ; path ++ )
302+ if (is_dir_sep (* path )) {
303+ do {
304+ path ++ ;
305+ } while (is_dir_sep (* path ));
306+ /* ignore trailing slashes */
307+ if (* path )
308+ basename = path ;
309+ }
310+
311+ if (hide_dotfiles == HIDE_DOTFILES_TRUE )
312+ return * basename == '.' ;
313+
314+ assert (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY );
315+ return !strncasecmp (".git" , basename , 4 ) &&
316+ (!basename [4 ] || is_dir_sep (basename [4 ]));
317+ }
318+
319+ static int set_hidden_flag (const wchar_t * path , int set )
320+ {
321+ DWORD original = GetFileAttributesW (path ), modified ;
322+ if (set )
323+ modified = original | FILE_ATTRIBUTE_HIDDEN ;
324+ else
325+ modified = original & ~FILE_ATTRIBUTE_HIDDEN ;
326+ if (original == modified || SetFileAttributesW (path , modified ))
327+ return 0 ;
328+ errno = err_win_to_posix (GetLastError ());
329+ return -1 ;
330+ }
331+
289332int mingw_mkdir (const char * path , int mode )
290333{
291334 int ret ;
292335 wchar_t wpath [MAX_PATH ];
293336 if (xutftowcs_path (wpath , path ) < 0 )
294337 return -1 ;
295338 ret = _wmkdir (wpath );
339+ if (!ret && needs_hiding (path ))
340+ return set_hidden_flag (wpath , 1 );
296341 return ret ;
297342}
298343
@@ -319,6 +364,21 @@ int mingw_open (const char *filename, int oflags, ...)
319364 if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY ))
320365 errno = EISDIR ;
321366 }
367+ if ((oflags & O_CREAT ) && needs_hiding (filename )) {
368+ /*
369+ * Internally, _wopen() uses the CreateFile() API which errors
370+ * out with an ERROR_ACCESS_DENIED if CREATE_ALWAYS was
371+ * specified and an already existing file's attributes do not
372+ * match *exactly*. As there is no mode or flag we can set that
373+ * would correspond to FILE_ATTRIBUTE_HIDDEN, let's just try
374+ * again *without* the O_CREAT flag (that corresponds to the
375+ * CREATE_ALWAYS flag of CreateFile()).
376+ */
377+ if (fd < 0 && errno == EACCES )
378+ fd = _wopen (wfilename , oflags & ~O_CREAT , mode );
379+ if (fd >= 0 && set_hidden_flag (wfilename , 1 ))
380+ warning ("could not mark '%s' as hidden." , filename );
381+ }
322382 return fd ;
323383}
324384
@@ -350,27 +410,41 @@ int mingw_fgetc(FILE *stream)
350410#undef fopen
351411FILE * mingw_fopen (const char * filename , const char * otype )
352412{
413+ int hide = needs_hiding (filename );
353414 FILE * file ;
354415 wchar_t wfilename [MAX_PATH ], wotype [4 ];
355416 if (filename && !strcmp (filename , "/dev/null" ))
356417 filename = "nul" ;
357418 if (xutftowcs_path (wfilename , filename ) < 0 ||
358419 xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
359420 return NULL ;
421+ if (hide && !access (filename , F_OK ) && set_hidden_flag (wfilename , 0 )) {
422+ error ("could not unhide %s" , filename );
423+ return NULL ;
424+ }
360425 file = _wfopen (wfilename , wotype );
426+ if (file && hide && set_hidden_flag (wfilename , 1 ))
427+ warning ("could not mark '%s' as hidden." , filename );
361428 return file ;
362429}
363430
364431FILE * mingw_freopen (const char * filename , const char * otype , FILE * stream )
365432{
433+ int hide = needs_hiding (filename );
366434 FILE * file ;
367435 wchar_t wfilename [MAX_PATH ], wotype [4 ];
368436 if (filename && !strcmp (filename , "/dev/null" ))
369437 filename = "nul" ;
370438 if (xutftowcs_path (wfilename , filename ) < 0 ||
371439 xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
372440 return NULL ;
441+ if (hide && !access (filename , F_OK ) && set_hidden_flag (wfilename , 0 )) {
442+ error ("could not unhide %s" , filename );
443+ return NULL ;
444+ }
373445 file = _wfreopen (wfilename , wotype , stream );
446+ if (file && hide && set_hidden_flag (wfilename , 1 ))
447+ warning ("could not mark '%s' as hidden." , filename );
374448 return file ;
375449}
376450
0 commit comments