Stupid winsock needs special way to close sockets.
[dftpd.git] / Filesystem.cpp
blobd392ce296880d6d12487526ce8c48141904b612d
1 #include <sys/stat.h>
2 #include <time.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <boost/lexical_cast.hpp>
6 #include "Filesystem.hpp"
7 #include "IO.hpp"
8 #include "String.hpp"
10 Filesystem::Filesystem( const std::string& root )
11 : m_root( root )
12 , m_path( "/" )
14 #ifdef SYMBIAN
15 m_rfs.Connect();
16 #endif
19 Filesystem::~Filesystem()
21 #ifdef SYMBIAN
22 m_rfs.Close();
23 #endif
26 bool Filesystem::ChangeDirectory( const std::string& cd )
28 PathVector reqPath = SplitPath( cd );
29 PathVector path = SplitProperPath( cd );
31 if( !TryChangePath( reqPath, path ) )
33 return false;
36 m_path = MakePath( path );
38 return true;
41 bool Filesystem::FileExists( const std::string& file )
43 return CheckFileExists( GetFilePath( file ) );
46 FILE* Filesystem::FileOpen( const std::string& file, Mode mode )
48 std::string path = m_root + GetFilePath( file );
50 switch( mode )
52 case M_READ:
53 return fopen( path.c_str(), "rb" );
54 break;
56 case M_WRITE:
57 return fopen( path.c_str(), "wb" );
58 break;
60 default:
61 break;
64 return NULL;
67 #ifdef SYMBIAN
68 RFile* Filesystem::FileOpenSymbian( const std::string& file, Mode mode )
70 RFile* f = new RFile;
72 std::string path = m_root + GetFilePath( file );
74 for( unsigned int i=0; i<path.size(); i++ )
76 if( path[i] == '/' || path[i] == '\\' )
78 if( i>0 && path[i-1] == '\\' )
80 path.erase( i, 1 );
81 i--;
83 else
85 path[i] = '\\';
90 TPtrC8 ptr( reinterpret_cast<const TUint8*>( path.c_str() ) );
91 TBuf<512> buf;
92 buf.FillZ();
93 buf.Copy( ptr );
95 switch( mode )
97 case M_READ:
98 if( f->Open( m_rfs, buf, EFileRead | EFileStream | EFileShareReadersOnly ) != KErrNone )
100 delete f;
101 f = NULL;
103 break;
105 case M_WRITE:
106 if( f->Replace( m_rfs, buf, EFileWrite | EFileStream ) != KErrNone )
108 delete f;
109 f = NULL;
111 break;
113 default:
114 delete f;
115 f = NULL;
116 break;
119 return f;
121 #endif
123 std::list<std::string> Filesystem::GetListing( const std::string& path )
125 std::list<std::string> ret;
127 time_t now = time( NULL );
129 std::string filePath = GetFilePath( path );
130 if( CheckFileExists( filePath ) )
132 struct stat s;
133 stat( ( m_root + filePath ).c_str(), &s );
135 std::string entry = "-rw-r--r--";
137 tm timeFile;
138 localtime_r( &s.st_mtime, &timeFile );
140 char dateBuf[64];
141 if( now > s.st_mtime && now - s.st_mtime < 60*60*24*180 )
143 // File is "recent"
144 strftime( dateBuf, sizeof( dateBuf ), " %b %m %H:%M ", &timeFile );
146 else
148 strftime( dateBuf, sizeof( dateBuf ), " %b %m %Y ", &timeFile );
151 entry += " 1 root root " + boost::lexical_cast<std::string>( s.st_size ) + dateBuf + path;
153 ret.push_back( entry );
155 return ret;
158 PathVector reqPath = SplitPath( path );
159 PathVector pv = SplitProperPath( path );
161 if( !TryChangePath( reqPath, pv ) )
163 return ret;
166 std::string newPath = m_root + MakePath( pv );
168 Directory d;
169 if( !d.Open( newPath ) )
171 return ret;
174 tm timeNow;
175 localtime_r( &now, &timeNow );
177 // Symbian readdir() doesn't report "." and ".."
178 bool hasDot = false;
179 bool hasDotDot = false;
181 struct stat s;
182 while( d )
184 std::string dirName = d.GetName();
185 stat( ( newPath + "/" + dirName ).c_str(), &s );
187 std::string entry;
189 if( S_ISDIR( s.st_mode ) )
191 entry += "drwxr-xr-x";
193 else
195 entry += "-rw-r--r--";
198 tm timeFile;
199 localtime_r( &s.st_mtime, &timeFile );
201 char dateBuf[64];
202 if( now > s.st_mtime && now - s.st_mtime < 60*60*24*180 )
204 // File is "recent"
205 strftime( dateBuf, sizeof( dateBuf ), " %b %m %H:%M ", &timeFile );
207 else
209 strftime( dateBuf, sizeof( dateBuf ), " %b %m %Y ", &timeFile );
212 entry += " 1 root root " + boost::lexical_cast<std::string>( s.st_size ) + dateBuf + dirName;
214 if( dirName == "." )
216 hasDot = true;
218 else if( dirName == ".." )
220 hasDotDot = true;
223 ret.push_back( entry );
225 ++d;
228 if( !hasDotDot )
230 ret.push_front( "drwxr-xr-x 1 root root 0 Jan 1 1970 .." );
232 if( !hasDot )
234 ret.push_front( "drwxr-xr-x 1 root root 0 Jan 1 1970 ." );
237 return ret;
240 bool Filesystem::Delete( const std::string& file )
242 std::string path = m_root + GetFilePath( file );
244 return unlink( path.c_str() ) == 0;
247 std::string Filesystem::MkDir( const std::string& dir )
249 std::string filePath = GetFilePath( dir );
250 if( filePath == "" )
252 return "";
255 std::string path = m_root + filePath;
257 if( !IO::MkDir( path ) )
259 return "";
262 return path;
265 bool Filesystem::RmDir( const std::string& dir )
267 std::string filePath = GetFilePath( dir );
268 if( filePath == "" )
270 return false;
273 std::string path = m_root + filePath;
275 if( !IO::RmDir( path ) )
277 return false;
280 return true;
283 std::string Filesystem::MakePath( const PathVector& pv )
285 std::string ret;
287 if( pv.size() == 0 )
289 ret = "/";
291 else
293 for( PathVector::const_iterator it = pv.begin(); it != pv.end(); ++it )
295 ret.append( "/" );
296 ret.append( *it );
300 return ret;
303 bool Filesystem::DirectoryExists( const std::string& dir )
305 std::string path = m_root + dir;
306 struct stat s;
308 if( stat( path.c_str(), &s ) == -1 )
310 return false;
313 return S_ISDIR( s.st_mode );
316 bool Filesystem::TryChangePath( const PathVector& reqPath, PathVector& path )
318 for( PathVector::const_iterator it = reqPath.begin(); it != reqPath.end(); ++it )
320 if( *it == "." )
322 continue;
324 else if( *it == ".." )
326 if( path.size() == 0 )
328 // Can't go below the root directory.
329 // Or maybe it should be possible as no-op?
330 return false;
332 else
334 path.pop_back();
337 else
339 if( DirectoryExists( MakePath( path ) + "/" + *it ) )
341 path.push_back( *it );
343 else
345 return false;
350 return true;
353 bool Filesystem::CheckFileExists( const std::string& file )
355 std::string path = m_root + file;
356 struct stat s;
358 if( stat( path.c_str(), &s ) == -1 )
360 return false;
363 return S_ISREG( s.st_mode );
366 std::string Filesystem::GetFilePath( const std::string& file )
368 PathVector reqPath = SplitPath( file );
370 if( reqPath.size() == 0 )
372 return "";
375 // Remove filename from path
376 std::string fname = reqPath.back();
377 reqPath.pop_back();
379 PathVector path = SplitProperPath( file );
381 if( !TryChangePath( reqPath, path ) )
383 return "";
386 return MakePath( path ) + "/" + fname;
389 PathVector Filesystem::SplitProperPath( const std::string& path )
391 PathVector ret;
393 if( path.length() > 0 &&
394 ( path[0] == '/' ||
395 ( path.length() > 1 && ( path[0] == '~' && path[1] == '/' ) ) ) )
397 ret = SplitPath( "/" );
399 else
401 ret = SplitPath( m_path );
404 return ret;