• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • Contact Us
 

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 }

kpimutils

Skip menu "kpimutils"
  • Main Page
  • Modules
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal