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