• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/File.cpp

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 
00020 #if defined(_WIN32) || defined(_WIN64)
00021 #include <spl/configwin32.h>
00022 #else
00023 #include <spl/autoconf/config.h>
00024 #endif
00025 
00026 #ifdef HAVE_ERRNO_H
00027 #include <errno.h>
00028 #endif
00029 #ifdef HAVE_FCNTL_H
00030 #include <fcntl.h>
00031 #endif
00032 #ifdef HAVE_SYS_TYPES_H
00033 #include <sys/types.h>
00034 #endif
00035 #ifdef HAVE_IO_H
00036 #include <io.h>
00037 #endif
00038 #ifdef HAVE_DIRECT_H
00039 #include <direct.h>
00040 #endif
00041 #ifdef HAVE_DIRENT_H
00042 #include <dirent.h>
00043 #endif
00044 #ifdef HAVE_SYS_STAT_H
00045 #include <sys/stat.h>
00046 #endif
00047 #ifdef HAVE_UNISTD_H
00048 #include <unistd.h>
00049 #endif
00050 #ifdef HAVE_SYS_STAT_H
00051 #include <sys/stat.h>
00052 #endif
00053 
00054 #include <spl/io/Directory.h>
00055 #include <spl/Environment.h>
00056 #include <spl/io/File.h>
00057 #include <spl/io/FileStream.h>
00058 #include <spl/Int32.h>
00059 #include <spl/io/WinPerm.h>
00060 
00061 #ifdef _WINDOWS
00062 extern bool EncodePermissions(const Permissions& perm, _WinPerms &wperm);
00063 extern bool DecodePermissions(_WinPerms &wperm, Permissions &perm);
00064 #include <Aclapi.h>
00065 #else
00066 extern void EncodePermissions(const Permissions& perm, mode_t& mode);
00067 extern void DecodePermissions(const mode_t mode, Permissions& perm);
00068 #endif
00069 
00070 FILE *_msokfopen(const char* filename, const char* mode)
00071 {
00072         #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
00073                 FILE* fp = 0;
00074                 errno_t err = fopen_s( &fp, File::ToOsFilePath(filename)->GetChars(), mode );
00075                 if ( !err && fp )
00076                         return fp;
00077                 return NULL;
00078         #else
00079                 return fopen( filename, mode );
00080         #endif
00081 }
00082 
00083 void File::Delete( const String& filename )
00084 {
00085         if (remove( ToOsFilePath(filename)->GetChars() ) != 0)
00086         {
00087                 throw new IOException(Environment::LastErrorMessage());
00088         }
00089 }
00090 
00091 void File::Rename(const String& oldname, const String& newname)
00092 {
00093         if (rename(oldname.GetChars(), newname.GetChars()) != 0)
00094         {
00095                 throw new IOException(Environment::LastErrorMessage());
00096         }
00097 }
00098 
00099 bool File::Exists( const String& filename )
00100 {
00101         bool ret = false;
00102         FILE *fp = _msokfopen(filename.GetChars(), "r");
00103         if ( NULL != fp )
00104         {
00105                 ret = true;
00106                 fclose(fp);
00107         }
00108         return ret;
00109 }
00110 
00111 bool File::IsFile(const String& filename)
00112 {
00113 #ifdef WIN32
00114 
00115         struct _stat stbuf;
00116         if(::_stat(Directory::RemoveTrailingSeperator(filename)->GetChars(), &stbuf) != 0)
00117         {
00118                 return false;
00119         }
00120 
00121         return (stbuf.st_mode & _S_IFREG) != 0;
00122 
00123 #else
00124 
00125         struct stat stbuf;
00126         if(::stat(filename.GetChars(), &stbuf) != 0)
00127         {
00128                 return false;
00129         }
00130         return S_ISREG(stbuf.st_mode);
00131 
00132 #endif
00133 }
00134 
00135 spl::IStreamPtr File::Create( const String& filename )
00136 {
00137         return FileStreamPtr(new FileStream(ToOsFilePath(filename)->GetChars(), File::FILEMODE_OpenOrCreate, File::FILEACC_ReadWrite));
00138 }
00139 
00140 void File::Copy( const String& sourcefile, const String& destfile )
00141 {
00142         Copy(sourcefile, destfile, false);
00143 }
00144 
00145 void File::Copy( const String& sourcefile, const String& destfile, bool overwrite )
00146 {
00147         if ( ! File::Exists(sourcefile) )
00148         {
00149                 throw new InvalidArgumentException("Source file not found.");
00150         }
00151         if ( !overwrite && File::Exists(destfile) )
00152         {
00153                 throw new IOException("Destination file exists");
00154         }
00155 
00156 #ifdef _WINDOWS
00157 
00158         if(::CopyFile(sourcefile.GetChars(), destfile.GetChars(), overwrite ? FALSE : TRUE) != TRUE)
00159         {
00160                 throw new IOException(Environment::LastErrorMessage());
00161         }
00162 
00163 #else
00164 
00165         #define BUFSIZE 256
00166 
00167         FILE *fpfrom, *fpto;
00168         char mode[5];
00169         char buf[BUFSIZE];
00170 
00171         strcpy(mode, "r");
00172         if ( /*binary*/true )
00173         {
00174                 strcat(mode, "b");
00175         }
00176         if ( NULL == (fpfrom = _msokfopen(sourcefile.GetChars(), mode)) )
00177         {
00178                 throw new IOException(Environment::LastErrorMessage());
00179         }
00180         strcpy(mode, "w");
00181         if ( /*binary*/true )
00182         {
00183                 strcat(mode, "b");
00184         }
00185         if ( NULL == (fpto = _msokfopen(destfile.GetChars(), mode)) )
00186         {
00187                 fclose( fpfrom );
00188                 throw new IOException(Environment::LastErrorMessage());
00189         }
00190         while ( ! feof( fpfrom ) )
00191         {
00192                 size_t len = fread(buf, 1, BUFSIZE, fpfrom);
00193                 if ( fwrite(buf, 1, len, fpto) != len )
00194                 {
00195                         fclose( fpto );
00196                         fclose( fpfrom );
00197                         throw new IOException(Environment::LastErrorMessage());
00198                 }
00199         }
00200         fclose( fpto );
00201         fclose( fpfrom );
00202 
00203 #endif
00204 }
00205 
00206 RefCountPtr<Array<byte> > File::LoadBinary( const String& filename )
00207 {
00208         int size;
00209 
00210 #ifdef _WINDOWS
00211     struct _finddata_t c_file;
00212 #if _MSC_VER >= 1400
00213     intptr_t hFile;
00214 #else
00215     long hFile;
00216 #endif
00217     if( (hFile = _findfirst( ToOsFilePath(filename)->GetChars(), &c_file )) == -1 )
00218         {
00219                 return RefCountPtr<Array<byte> >();
00220         }
00221         size = c_file.size;
00222         _findclose( hFile );
00223 #else
00224         struct stat st;
00225         stat(filename.GetChars(), &st);
00226         size = st.st_size;
00227 #endif
00228 
00229         FILE *fp = _msokfopen(filename.GetChars(), "rb");
00230         if ( NULL == fp )
00231         {
00232                 return RefCountPtr<Array<byte> >();
00233         }
00234 
00235         RefCountPtr<Array<byte> > buf( new Array<byte>(size) );
00236         if ( size != (int)fread(buf.Get(), 1, size, fp) )
00237         {
00238                 return RefCountPtr<Array<byte> >();
00239         }
00240         return buf;
00241 }
00242 
00243 StringPtr File::LoadText( const String& filename )
00244 {
00245         int size;
00246 
00247 #ifdef _WINDOWS
00248     struct _finddata_t c_file;
00249 #if _MSC_VER >= 1400
00250     intptr_t hFile;
00251 #else
00252     long hFile;
00253 #endif
00254     if( (hFile = _findfirst( ToOsFilePath(filename)->GetChars(), &c_file )) == -1 )
00255         {
00256                 return StringPtr();
00257         }
00258         size = c_file.size;
00259         _findclose( hFile );
00260 #else
00261         struct stat st;
00262         stat(filename.GetChars(), &st);
00263         if (0 == (size = st.st_size))
00264         {
00265                 size = 1024;
00266         }
00267 #endif
00268 
00269         FILE *fp = _msokfopen(filename.GetChars(), "r");
00270         if ( NULL == fp )
00271         {
00272                 return StringPtr();
00273         }
00274 
00275         const int cbufSize = 512;
00276         char cbuf[cbufSize];
00277         StringBuffer buf( size );
00278         int count;
00279 
00280         while ((count = (int)fread(cbuf, 1, cbufSize, fp) ) > 0)
00281         {
00282                 buf.Append(cbuf, 0, count);
00283         }
00284         return buf.ToString();
00285 }
00286 
00287 StringPtr File::ToOsFilePath( const String& filepathname )
00288 {
00289 #ifdef _WIN32
00290         return filepathname.Replace('/', '\\');
00291 #else
00292         StringPtr fpn = filepathname.Replace('\\', '/');
00293         if ( fpn->IndexOf(':') > -1 )
00294         {
00295                 throw new InvalidArgumentException("Colons not allowed in unix file names");
00296         }
00297         return fpn;
00298 #endif
00299 }
00300 
00301 StringPtr File::GetFileName( const String& filepathname )
00302 {
00303         char sep[2];
00304         sep[0] = Directory::SeperatorChar();
00305         sep[1] = '\0';
00306         RefCountPtr<Vector<StringPtr> > parts = filepathname.Split(sep);
00307         if (parts->Count() == 0)
00308         {
00309                 return StringPtr(new String());
00310         }
00311         return parts->ElementAt(parts->Count() -1);
00312 }
00313 
00314 TextWriterPtr File::AppendText( const String& filename )
00315 {
00316         return TextWriterPtr(new TextWriter(FileStreamPtr(new FileStream(*ToOsFilePath(filename), File::FILEMODE_Append, File::FILEACC_Write))));
00317 }
00318 
00319 TextWriterPtr File::CreateText( const String& filename )
00320 {
00321         return TextWriterPtr(new TextWriter( FileStreamPtr(new FileStream(*ToOsFilePath(filename), File::FILEMODE_Create, File::FILEACC_ReadWrite )) ));
00322 }
00323 
00324 TextReaderPtr File::ReadText( const String& filename )
00325 {
00326         return TextReaderPtr(new TextReader( FileStreamPtr(new FileStream(*ToOsFilePath(filename), File::FILEMODE_Open, File::FILEACC_Read )) ));
00327 }
00328 
00329 spl::IStreamPtr File::Open( const String& filename, FileMode mode )
00330 {
00331         return FileStreamPtr(new FileStream(*ToOsFilePath(filename), mode, File::FILEACC_ReadWrite ));
00332 }
00333 
00334 spl::IStreamPtr File::Open( const String& filename, FileMode mode, FileAccess access )
00335 {
00336         return FileStreamPtr(new FileStream(*ToOsFilePath(filename), mode, access));
00337 }
00338 
00339 spl::IStreamPtr File::OpenRead( const String& filename )
00340 {
00341         return FileStreamPtr(new FileStream(*ToOsFilePath(filename), File::FILEMODE_Open, File::FILEACC_Read));
00342 }
00343 
00344 spl::IStreamPtr File::OpenText( const String& filename )
00345 {
00346         return FileStreamPtr(new FileStream(*ToOsFilePath(filename), File::FILEMODE_Open, File::FILEACC_ReadWrite));
00347 }
00348 
00349 spl::IStreamPtr File::OpenWrite( const String& filename )
00350 {
00351         return FileStreamPtr(new FileStream(*ToOsFilePath(filename), File::FILEMODE_Open, File::FILEACC_Write ));
00352 }
00353 
00354 long File::Size( const String& filename )
00355 {
00356         struct stat file_stats;
00357         if(0 != stat(ToOsFilePath(filename)->GetChars(), &file_stats))
00358     {
00359                 throw new IOException(Environment::LastErrorMessage());
00360         }                
00361         return (long)file_stats.st_size;
00362 }
00363 
00364 DateTime File::GetCreationTime( const String& filename )
00365 {
00366         struct stat file_stats;
00367         if(0 != stat(ToOsFilePath(filename)->GetChars(), &file_stats))
00368     {
00369                 throw new IOException(Environment::LastErrorMessage());
00370         }                
00371         return DateTime(file_stats.st_ctime);
00372 }
00373 
00374 DateTime File::GetLastAccessTime( const String& filename )
00375 {
00376         struct stat file_stats;
00377         if(0 != stat(ToOsFilePath(filename)->GetChars(), &file_stats))
00378     {
00379                 throw new IOException(Environment::LastErrorMessage());
00380         }                
00381         return DateTime(file_stats.st_atime);
00382 }
00383 
00384 DateTime File::GetLastWriteTime( const String& filename )
00385 {
00386         struct stat file_stats;
00387         if(0 != stat(ToOsFilePath(filename)->GetChars(), &file_stats))
00388     {
00389                 throw new IOException(Environment::LastErrorMessage());
00390         }                
00391         return DateTime(file_stats.st_mtime);
00392 }
00393 
00394 Permissions File::GetPermissions(const String& filename)
00395 {
00396         Permissions perms;
00397 
00398 #ifdef _WINDOWS
00399 
00400         _WinPerms wperm; // needs members to be the above crap
00401 
00402         if(::GetNamedSecurityInfo((LPTSTR)(Directory::RemoveTrailingSeperator(filename)->GetChars()),
00403                                                         SE_FILE_OBJECT,
00404                                                         (OWNER_SECURITY_INFORMATION
00405                                                          | GROUP_SECURITY_INFORMATION
00406                                                          | DACL_SECURITY_INFORMATION),
00407                                                         &wperm.user, &wperm.group, &wperm.dacl, NULL,
00408                                                         &wperm.pdesc) != ERROR_SUCCESS)
00409         {
00410                 throw new IOException(Environment::LastErrorMessage());
00411         }
00412         
00413         DecodePermissions(wperm, perms);
00414 
00415 #else
00416 
00417         struct stat stbuf;
00418 
00419         if(::stat(filename.GetChars(), &stbuf) != 0)
00420         {
00421                 throw new IOException("stat error");
00422         }
00423 
00424         DecodePermissions(stbuf.st_mode, perms);
00425 
00426 #endif
00427 
00428         return perms;
00429 }
00430 
00431 void File::SetPermissions(const String& filename, const Permissions& perms)
00432 {
00433 #ifdef WIN32
00434 
00435         _WinPerms wperm;
00436 
00437         if(! EncodePermissions(perms, wperm))
00438         {
00439                 throw new IOException(Environment::LastErrorMessage());
00440         }
00441 
00442         if(::SetFileSecurity(Directory::RemoveTrailingSeperator(filename)->GetChars(), DACL_SECURITY_INFORMATION, wperm.pdesc) != TRUE)
00443         {
00444                 throw new IOException(Environment::LastErrorMessage());
00445         }
00446 
00447 #else
00448 
00449         mode_t mode;
00450         EncodePermissions(perms, mode);
00451 
00452         if(::chmod(filename.GetChars(), mode) != 0)
00453         {
00454                 throw new IOException(Environment::LastErrorMessage());
00455         }
00456 
00457 #endif
00458 }
00459 
00460 void File::Move(const String &oldFile, const String &newFile)
00461 {
00462 #ifdef WIN32
00463 
00464         if(::MoveFile(Directory::RemoveTrailingSeperator(oldFile)->GetChars(), Directory::RemoveTrailingSeperator(newFile)->GetChars()) != TRUE)
00465         {
00466                 throw new IOException(Environment::LastErrorMessage());
00467         }
00468 
00469 #else
00470 
00471         int r = ::link(oldFile.GetChars(), newFile.GetChars());
00472         if(r != 0)
00473         {
00474                 throw new IOException(Environment::LastErrorMessage());
00475         }
00476 
00477         if(::unlink(oldFile.GetChars()) != 0)
00478         {
00479                 ::unlink(newFile.GetChars());
00480 
00481                 throw new IOException(Environment::LastErrorMessage());
00482         }
00483 
00484 #endif
00485 }