kpimutils
kfileio.cpp
00001 /* 00002 Copyright (c) 2005 Tom Albers <tomalbers@kde.nl> 00003 Copyright (c) 1997-1999 Stefan Taferner <taferner@kde.org> 00004 00005 This library is free software; you can redistribute it and/or modify it 00006 under the terms of the GNU Library General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or (at your 00008 option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, but WITHOUT 00011 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to the 00017 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00018 02110-1301, USA. 00019 */ 00020 00021 #include "kfileio.h" 00022 #include "kpimutils_export.h" 00023 00024 #include <KDebug> 00025 #include <KLocale> 00026 #include <KMessageBox> 00027 #include <KStandardGuiItem> 00028 #include <kde_file.h> //krazy:exclude=camelcase 00029 00030 #include <QDir> 00031 #include <QByteArray> 00032 #include <QWidget> 00033 #include <QFile> 00034 #include <QFileInfo> 00035 00036 #include <sys/stat.h> 00037 #include <sys/types.h> 00038 #include <assert.h> 00039 00040 namespace KPIMUtils { 00041 00042 //----------------------------------------------------------------------------- 00043 static void msgDialog( const QString &msg ) 00044 { 00045 KMessageBox::sorry( 0, msg, i18n( "File I/O Error" ) ); 00046 } 00047 00048 //----------------------------------------------------------------------------- 00049 QByteArray kFileToByteArray( const QString &aFileName, bool aEnsureNL, 00050 bool aVerbose ) 00051 { 00052 QByteArray result; 00053 QFileInfo info( aFileName ); 00054 unsigned int readLen; 00055 unsigned int len = info.size(); 00056 QFile file( aFileName ); 00057 00058 //assert(aFileName!=0); 00059 if( aFileName.isEmpty() ) { 00060 return ""; 00061 } 00062 00063 if ( !info.exists() ) { 00064 if ( aVerbose ) { 00065 msgDialog( i18n( "The specified file does not exist:\n%1", aFileName ) ); 00066 } 00067 return QByteArray(); 00068 } 00069 if ( info.isDir() ) { 00070 if ( aVerbose ) { 00071 msgDialog( i18n( "This is a folder and not a file:\n%1", aFileName ) ); 00072 } 00073 return QByteArray(); 00074 } 00075 if ( !info.isReadable() ) { 00076 if ( aVerbose ) { 00077 msgDialog( i18n( "You do not have read permissions to the file:\n%1", aFileName ) ); 00078 } 00079 return QByteArray(); 00080 } 00081 if ( len <= 0 ) { 00082 return QByteArray(); 00083 } 00084 00085 if ( !file.open( QIODevice::Unbuffered|QIODevice::ReadOnly ) ) { 00086 if ( aVerbose ) { 00087 switch( file.error() ) { 00088 case QFile::ReadError: 00089 msgDialog( i18n( "Could not read file:\n%1", aFileName ) ); 00090 break; 00091 case QFile::OpenError: 00092 msgDialog( i18n( "Could not open file:\n%1", aFileName ) ); 00093 break; 00094 default: 00095 msgDialog( i18n( "Error while reading file:\n%1", aFileName ) ); 00096 } 00097 } 00098 return QByteArray(); 00099 } 00100 00101 result.resize( len + int( aEnsureNL ) ); 00102 readLen = file.read( result.data(), len ); 00103 if ( aEnsureNL ) { 00104 if ( result[readLen-1] != '\n' ) { 00105 result[readLen++] = '\n'; 00106 len++; 00107 } else { 00108 result.truncate( len ); 00109 } 00110 } 00111 00112 if ( readLen < len ) { 00113 QString msg = i18np( "Could only read 1 byte of %2.", 00114 "Could only read %1 bytes of %2.", 00115 readLen, len ); 00116 msgDialog( msg ); 00117 result.truncate( readLen ); 00118 } 00119 00120 return result; 00121 } 00122 00123 //----------------------------------------------------------------------------- 00124 bool kByteArrayToFile( const QByteArray &aBuffer, const QString &aFileName, 00125 bool aAskIfExists, bool aBackup, bool aVerbose ) 00126 { 00127 // TODO: use KSaveFile 00128 QFile file( aFileName ); 00129 00130 //assert(aFileName!=0); 00131 if( aFileName.isEmpty() ) { 00132 return false; 00133 } 00134 00135 if ( file.exists() ) { 00136 if ( aAskIfExists ) { 00137 QString str; 00138 str = i18n( "File %1 exists.\nDo you want to replace it?", aFileName ); 00139 const int rc = 00140 KMessageBox::warningContinueCancel( 0, str, i18n( "Save to File" ), 00141 KGuiItem( i18n( "&Replace" ) ) ); 00142 if ( rc != KMessageBox::Continue ) { 00143 return false; 00144 } 00145 } 00146 if ( aBackup ) { 00147 // make a backup copy 00148 // TODO: use KSaveFile::backupFile() 00149 QString bakName = aFileName; 00150 bakName += '~'; 00151 QFile::remove(bakName); 00152 if ( !QDir::current().rename( aFileName, bakName ) ) { 00153 // failed to rename file 00154 if ( !aVerbose ) { 00155 return false; 00156 } 00157 const int rc = 00158 KMessageBox::warningContinueCancel( 00159 0, 00160 i18n( "Failed to make a backup copy of %1.\nContinue anyway?", aFileName ), 00161 i18n( "Save to File" ), KStandardGuiItem::save() ); 00162 00163 if ( rc != KMessageBox::Continue ) { 00164 return false; 00165 } 00166 } 00167 } 00168 } 00169 00170 if ( !file.open( QIODevice::Unbuffered|QIODevice::WriteOnly|QIODevice::Truncate ) ) { 00171 if ( aVerbose ) { 00172 switch( file.error() ) { 00173 case QFile::WriteError: 00174 msgDialog( i18n( "Could not write to file:\n%1", aFileName ) ); 00175 break; 00176 case QFile::OpenError: 00177 msgDialog( i18n( "Could not open file for writing:\n%1", aFileName ) ); 00178 break; 00179 default: 00180 msgDialog( i18n( "Error while writing file:\n%1", aFileName ) ); 00181 } 00182 } 00183 return false; 00184 } 00185 00186 const int writeLen = file.write( aBuffer.data(), aBuffer.size() ); 00187 00188 if ( writeLen < 0 ) { 00189 if ( aVerbose ) { 00190 msgDialog( i18n( "Could not write to file:\n%1", aFileName ) ); 00191 } 00192 return false; 00193 } else if ( writeLen < aBuffer.size() ) { 00194 QString msg = i18np( "Could only write 1 byte of %2.", 00195 "Could only write %1 bytes of %2.", 00196 writeLen, aBuffer.size() ); 00197 if ( aVerbose ) { 00198 msgDialog( msg ); 00199 } 00200 return false; 00201 } 00202 00203 return true; 00204 } 00205 00206 QString checkAndCorrectPermissionsIfPossible( const QString &toCheck, 00207 const bool recursive, 00208 const bool wantItReadable, 00209 const bool wantItWritable ) 00210 { 00211 // First we have to find out which type the toCheck is. This can be 00212 // a directory (follow if recursive) or a file (check permissions). 00213 // Symlinks are followed as expected. 00214 QFileInfo fiToCheck(toCheck); 00215 fiToCheck.setCaching(false); 00216 QByteArray toCheckEnc = QFile::encodeName( toCheck ); 00217 QString error; 00218 KDE_struct_stat statbuffer; 00219 00220 if ( !fiToCheck.exists() ) { 00221 error.append( i18n( "%1 does not exist", toCheck ) + '\n' ); 00222 } 00223 00224 // check the access bit of a folder. 00225 if ( fiToCheck.isDir() ) { 00226 if ( KDE_stat( toCheckEnc,&statbuffer ) != 0 ) { 00227 kDebug() << "wantItA: Can't read perms of" << toCheck; 00228 } 00229 QDir g( toCheck ); 00230 if ( !g.isReadable() ) { 00231 if ( chmod( toCheckEnc, statbuffer.st_mode + S_IXUSR ) != 0 ) { 00232 error.append( i18n( "%1 is not accessible and that is " 00233 "unchangeable.", toCheck ) + '\n' ); 00234 } else { 00235 kDebug() << "Changed access bit for" << toCheck; 00236 } 00237 } 00238 } 00239 00240 // For each file or folder we can check if the file is readable 00241 // and writable, as requested. 00242 if ( fiToCheck.isFile() || fiToCheck.isDir() ) { 00243 00244 if ( !fiToCheck.isReadable() && wantItReadable ) { 00245 // Get the current permissions. No need to do anything with an 00246 // error, it will het added to errors anyhow, later on. 00247 if ( KDE_stat( toCheckEnc,&statbuffer ) != 0 ) { 00248 kDebug() << "wantItR: Can't read perms of" << toCheck; 00249 } 00250 00251 // Lets try changing it. 00252 if ( chmod( toCheckEnc, statbuffer.st_mode + S_IRUSR ) != 0 ) { 00253 error.append( i18n( "%1 is not readable and that is unchangeable.", 00254 toCheck ) + '\n' ); 00255 } else { 00256 kDebug() << "Changed the read bit for" << toCheck; 00257 } 00258 } 00259 00260 if ( !fiToCheck.isWritable() && wantItWritable ) { 00261 // Gets the current persmissions. Needed because it can be changed 00262 // curing previous operation. 00263 if ( KDE_stat( toCheckEnc,&statbuffer ) != 0 ) { 00264 kDebug() << "wantItW: Can't read perms of" << toCheck; 00265 } 00266 00267 // Lets try changing it. 00268 if ( chmod ( toCheckEnc, statbuffer.st_mode + S_IWUSR ) != 0 ) { 00269 error.append( i18n( "%1 is not writable and that is unchangeable.", toCheck ) + '\n' ); 00270 } else { 00271 kDebug() << "Changed the write bit for" << toCheck; 00272 } 00273 } 00274 } 00275 00276 // If it is a folder and recursive is true, then we check the contents of 00277 // the folder. 00278 if ( fiToCheck.isDir() && recursive ){ 00279 QDir g( toCheck ); 00280 // First check if the folder is readable for us. If not, we get 00281 // some ugly crashes. 00282 if ( !g.isReadable() ){ 00283 error.append( i18n( "Folder %1 is inaccessible.", toCheck ) + '\n' ); 00284 } else { 00285 foreach ( const QFileInfo &fi, g.entryInfoList() ) { 00286 QString newToCheck = toCheck + '/' + fi.fileName(); 00287 QFileInfo fiNewToCheck(newToCheck); 00288 if ( fi.fileName() != "." && fi.fileName() != ".." ) { 00289 error.append ( 00290 checkAndCorrectPermissionsIfPossible( newToCheck, recursive, 00291 wantItReadable, wantItWritable ) ); 00292 } 00293 } 00294 } 00295 } 00296 return error; 00297 } 00298 00299 bool checkAndCorrectPermissionsIfPossibleWithErrorHandling( QWidget *parent, 00300 const QString &toCheck, 00301 const bool recursive, 00302 const bool wantItReadable, 00303 const bool wantItWritable ) 00304 { 00305 QString error = 00306 checkAndCorrectPermissionsIfPossible( toCheck, recursive, wantItReadable, wantItWritable ); 00307 00308 // There is no KMessageBox with Retry, Cancel and Details. 00309 // so, I can't provide a functionality to recheck. So it now 00310 // it is just a warning. 00311 if ( !error.isEmpty() ) { 00312 kDebug() << "checkPermissions found:" << error; 00313 KMessageBox::detailedSorry( parent, 00314 i18n( "Some files or folders do not have the " 00315 "necessary permissions, please correct " 00316 "them manually." ), 00317 error, i18n( "Permissions Check" ), 0 ); 00318 return false; 00319 } else { 00320 return true; 00321 } 00322 } 00323 00324 bool removeDirAndContentsRecursively( const QString & path ) 00325 { 00326 bool success = true; 00327 00328 QDir d; 00329 d.setPath( path ); 00330 d.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoSymLinks ); 00331 00332 QFileInfoList list = d.entryInfoList(); 00333 00334 Q_FOREACH( const QFileInfo &fi, list ) { 00335 if ( fi.isDir() ) { 00336 if ( fi.fileName() != "." && fi.fileName() != ".." ) { 00337 success = success && removeDirAndContentsRecursively( fi.absoluteFilePath() ); 00338 } 00339 } else { 00340 success = success && d.remove( fi.absoluteFilePath() ); 00341 } 00342 } 00343 00344 if ( success ) { 00345 success = success && d.rmdir( path ); // nuke ourselves, we should be empty now 00346 } 00347 return success; 00348 } 00349 00350 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:44:53 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:44:53 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.