1 // Copyright (c) 2012-2014 Konstantin Isakov <ikm@zbackup.org> and ZBackup contributors, see CONTRIBUTORS
2 // Part of ZBackup. Licensed under GNU GPLv2 or later + OpenSSL, see LICENSE
3 
4 #include <fcntl.h>
5 #include <libgen.h>
6 #include <stdlib.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <vector>
10 
11 #include "dir.hh"
12 
13 DIR * dir;
14 
15 namespace Dir {
exists(string const & name)16 bool exists( string const & name )
17 {
18   struct stat buf;
19 
20   return stat( name.c_str(), &buf ) == 0 && S_ISDIR( buf.st_mode );
21 }
22 
create(string const & name)23 void create( string const & name )
24 {
25   if ( mkdir( name.c_str(), 0777 ) != 0 )
26     throw exCantCreate( name );
27 }
28 
remove(string const & name)29 void remove( string const & name )
30 {
31   if ( rmdir( name.c_str() ) != 0 )
32     throw exCantRemove( name );
33 }
34 
addPath(string const & first,string const & second)35 string addPath( string const & first, string const & second )
36 {
37   if ( first.empty() )
38     return second;
39 
40   if ( second.empty() )
41     return first;
42 
43   if ( first[ first.size() - 1 ] == separator() )
44     return first + second;
45   else
46     return first + separator() + second;
47 }
48 
getRealPath(string const & path)49 string getRealPath( string const & path )
50 {
51   if ( char * r = realpath( path.c_str(), NULL ) )
52   {
53     string result( r );
54     free( r );
55     return result;
56   }
57   else
58     throw exCantGetRealPath( path );
59 }
60 
getDirName(string const & path)61 string getDirName( string const & path )
62 {
63   char const * c = path.c_str();
64   std::vector< char > copy( c, c + path.size() + 1 );
65 
66   return dirname( copy.data() );
67 }
68 
isDirEmpty(string const & path)69 bool isDirEmpty( string const & path )
70 {
71   Listing lst(path);
72   Entry tmp;
73   return !lst.getNext(tmp);
74 }
75 
Listing(string const & dirName)76 Listing::Listing( string const & dirName ): dirName( dirName )
77 {
78   dir = opendir( dirName.c_str() );
79 
80   if ( !dir )
81     throw exCantList( dirName );
82 
83 }
84 
~Listing()85 Listing::~Listing()
86 {
87   closedir( dir );
88 }
89 
getNext(Entry & result)90 bool Listing::getNext( Entry & result )
91 {
92   dirent entry;
93 
94   dirent * entryPtr;
95 
96   struct stat entryStats;
97 
98   for ( ; ; )
99   {
100     if ( readdir_r( dir, &entry, &entryPtr ) != 0 )
101       throw exCantList( dirName );
102 
103     if ( !entryPtr )
104       return false;
105 
106 #if !defined(__APPLE__) && !defined(__FreeBSD__)
107     if ( fstatat( dirfd( dir ), entry.d_name, &entryStats,
108                   AT_SYMLINK_NOFOLLOW ) != 0 )
109 #else
110     if ( lstat( addPath( dirName, entry.d_name ).c_str(),
111                 &entryStats ) != 0)
112 #endif
113       throw exCantList( dirName );
114 
115     bool isDir = S_ISDIR( entryStats.st_mode );
116     bool isSymLink = S_ISLNK( entryStats.st_mode );
117 
118     if ( isDir &&
119          ( entry.d_name[ 0 ] == '.' &&
120            ( !entry.d_name[ 1 ] || entry.d_name[ 1 ] == '.' ) ) )
121     {
122       // Skip the . or .. entries
123       continue;
124     }
125 
126     result = Entry( entry.d_name, isDir, isSymLink );
127     return true;
128   }
129 }
130 
131 }
132