@ -14,10 +14,10 @@
*/
# ifndef FRONTEND
# error "This file is not expected to be compiled for backend code"
# endif
# include "postgres.h"
# else
# include "postgres_fe.h"
# endif
# include <dirent.h>
# include <fcntl.h>
@ -25,8 +25,11 @@
# include <unistd.h>
# include "common/file_utils.h"
# ifdef FRONTEND
# include "common/logging.h"
# endif
# ifdef FRONTEND
/* Define PG_FLUSH_DATA_WORKS if we have an implementation for pg_flush_data */
# if defined(HAVE_SYNC_FILE_RANGE)
@ -167,8 +170,6 @@ walkdir(const char *path,
while ( errno = 0 , ( de = readdir ( dir ) ) ! = NULL )
{
char subpath [ MAXPGPATH * 2 ] ;
struct stat fst ;
int sret ;
if ( strcmp ( de - > d_name , " . " ) = = 0 | |
strcmp ( de - > d_name , " .. " ) = = 0 )
@ -176,21 +177,23 @@ walkdir(const char *path,
snprintf ( subpath , sizeof ( subpath ) , " %s/%s " , path , de - > d_name ) ;
if ( process_symlinks )
sret = stat ( subpath , & fst ) ;
else
sret = lstat ( subpath , & fst ) ;
if ( sret < 0 )
switch ( get_dirent_type ( subpath , de , process_symlinks , PG_LOG_ERROR ) )
{
pg_log_error ( " could not stat file \" %s \" : %m " , subpath ) ;
continue ;
case PGFILETYPE_REG :
( * action ) ( subpath , false ) ;
break ;
case PGFILETYPE_DIR :
walkdir ( subpath , action , false ) ;
break ;
default :
/*
* Errors are already reported directly by get_dirent_type ( ) ,
* and any remaining symlinks and unknown file types are
* ignored .
*/
break ;
}
if ( S_ISREG ( fst . st_mode ) )
( * action ) ( subpath , false ) ;
else if ( S_ISDIR ( fst . st_mode ) )
walkdir ( subpath , action , false ) ;
}
if ( errno )
@ -394,3 +397,73 @@ durable_rename(const char *oldfile, const char *newfile)
return 0 ;
}
# endif /* FRONTEND */
/*
* Return the type of a directory entry .
*
* In frontend code , elevel should be a level from logging . h ; in backend code
* it should be a level from elog . h .
*/
PGFileType
get_dirent_type ( const char * path ,
const struct dirent * de ,
bool look_through_symlinks ,
int elevel )
{
PGFileType result ;
/*
* Some systems tell us the type directly in the dirent struct , but that ' s
* a BSD and Linux extension not required by POSIX . Even when the
* interface is present , sometimes the type is unknown , depending on the
* filesystem .
*/
# if defined(DT_REG) && defined(DT_DIR) && defined(DT_LNK)
if ( de - > d_type = = DT_REG )
result = PGFILETYPE_REG ;
else if ( de - > d_type = = DT_DIR )
result = PGFILETYPE_DIR ;
else if ( de - > d_type = = DT_LNK & & ! look_through_symlinks )
result = PGFILETYPE_LNK ;
else
result = PGFILETYPE_UNKNOWN ;
# else
result = PGFILETYPE_UNKNOWN ;
# endif
if ( result = = PGFILETYPE_UNKNOWN )
{
struct stat fst ;
int sret ;
if ( look_through_symlinks )
sret = stat ( path , & fst ) ;
else
sret = lstat ( path , & fst ) ;
if ( sret < 0 )
{
result = PGFILETYPE_ERROR ;
# ifdef FRONTEND
pg_log_generic ( elevel , " could not stat file \" %s \" : %m " , path ) ;
# else
ereport ( elevel ,
( errcode_for_file_access ( ) ,
errmsg ( " could not stat file \" %s \" : %m " , path ) ) ) ;
# endif
}
else if ( S_ISREG ( fst . st_mode ) )
result = PGFILETYPE_REG ;
else if ( S_ISDIR ( fst . st_mode ) )
result = PGFILETYPE_DIR ;
# ifdef S_ISLNK
else if ( S_ISLNK ( fst . st_mode ) )
result = PGFILETYPE_LNK ;
# endif
}
return result ;
}