libkdepim

kfileio.cpp

00001 // kfileio.cpp
00002 // Author: Stefan Taferner <taferner@kde.org>
00003 // License: GPL
00004 
00005 #ifdef HAVE_CONFIG_H
00006 #include <config.h>
00007 #endif
00008 
00009 #include <kmessagebox.h>
00010 #include <kdebug.h>
00011 
00012 #include <assert.h>
00013 #include <qdir.h>
00014 
00015 #include <klocale.h>
00016 #include <kstdguiitem.h>
00017 
00018 #include <qwidget.h>
00019 #include <qfile.h>
00020 #include <qfileinfo.h>
00021 #include <sys/stat.h>
00022 #include <sys/types.h>
00023 
00024 #include <kdepimmacros.h>
00025 
00026 namespace KPIM {
00027 
00028 //-----------------------------------------------------------------------------
00029 static void msgDialog(const QString &msg)
00030 {
00031   KMessageBox::sorry(0, msg, i18n("File I/O Error"));
00032 }
00033 
00034 
00035 //-----------------------------------------------------------------------------
00036 KDE_EXPORT QCString kFileToString(const QString &aFileName, bool aEnsureNL, bool aVerbose)
00037 {
00038   QCString result;
00039   QFileInfo info(aFileName);
00040   unsigned int readLen;
00041   unsigned int len = info.size();
00042   QFile file(aFileName);
00043 
00044   //assert(aFileName!=0);
00045   if( aFileName.isEmpty() )
00046     return "";
00047 
00048   if (!info.exists())
00049   {
00050     if (aVerbose)
00051       msgDialog(i18n("The specified file does not exist:\n%1").arg(aFileName));
00052     return QCString();
00053   }
00054   if (info.isDir())
00055   {
00056     if (aVerbose)
00057       msgDialog(i18n("This is a folder and not a file:\n%1").arg(aFileName));
00058     return QCString();
00059   }
00060   if (!info.isReadable())
00061   {
00062     if (aVerbose)
00063       msgDialog(i18n("You do not have read permissions "
00064                    "to the file:\n%1").arg(aFileName));
00065     return QCString();
00066   }
00067   if (len <= 0) return QCString();
00068 
00069   if (!file.open(IO_Raw|IO_ReadOnly))
00070   {
00071     if (aVerbose) switch(file.status())
00072     {
00073     case IO_ReadError:
00074       msgDialog(i18n("Could not read file:\n%1").arg(aFileName));
00075       break;
00076     case IO_OpenError:
00077       msgDialog(i18n("Could not open file:\n%1").arg(aFileName));
00078       break;
00079     default:
00080       msgDialog(i18n("Error while reading file:\n%1").arg(aFileName));
00081     }
00082     return QCString();
00083   }
00084 
00085   result.resize(len + (int)aEnsureNL + 1);
00086   readLen = file.readBlock(result.data(), len);
00087   if (aEnsureNL && result[len-1]!='\n')
00088   {
00089     result[len++] = '\n';
00090     readLen++;
00091   }
00092   result[len] = '\0';
00093 
00094   if (readLen < len)
00095   {
00096     QString msg = i18n("Could only read %1 bytes of %2.")
00097         .arg(readLen).arg(len);
00098     msgDialog(msg);
00099     return QCString();
00100   }
00101 
00102   return result;
00103 }
00104 
00105 //-----------------------------------------------------------------------------
00106 #if 0 // unused
00107 QByteArray kFileToBytes(const QString &aFileName, bool aVerbose)
00108 {
00109   QByteArray result;
00110   QFileInfo info(aFileName);
00111   unsigned int readLen;
00112   unsigned int len = info.size();
00113   QFile file(aFileName);
00114 
00115   //assert(aFileName!=0);
00116   if( aFileName.isEmpty() )
00117     return result;
00118 
00119   if (!info.exists())
00120   {
00121     if (aVerbose)
00122       msgDialog(i18n("The specified file does not exist:\n%1")
00123         .arg(aFileName));
00124     return result;
00125   }
00126   if (info.isDir())
00127   {
00128     if (aVerbose)
00129       msgDialog(i18n("This is a folder and not a file:\n%1")
00130         .arg(aFileName));
00131     return result;
00132   }
00133   if (!info.isReadable())
00134   {
00135     if (aVerbose)
00136       msgDialog(i18n("You do not have read permissions "
00137                    "to the file:\n%1").arg(aFileName));
00138     return result;
00139   }
00140   if (len <= 0) return result;
00141 
00142   if (!file.open(IO_Raw|IO_ReadOnly))
00143   {
00144     if (aVerbose) switch(file.status())
00145     {
00146     case IO_ReadError:
00147       msgDialog(i18n("Could not read file:\n%1").arg(aFileName));
00148       break;
00149     case IO_OpenError:
00150       msgDialog(i18n("Could not open file:\n%1").arg(aFileName));
00151       break;
00152     default:
00153       msgDialog(i18n("Error while reading file:\n%1").arg(aFileName));
00154     }
00155     return result;
00156   }
00157 
00158   result.resize(len);
00159   readLen = file.readBlock(result.data(), len);
00160   kdDebug(5300) << QString( "len %1" ).arg(len) << endl;
00161 
00162   if (readLen < len)
00163   {
00164     QString msg;
00165     msg = i18n("Could only read %1 bytes of %2.")
00166         .arg(readLen).arg(len);
00167     msgDialog(msg);
00168     return result;
00169   }
00170 
00171   return result;
00172 }
00173 #endif
00174 
00175 //-----------------------------------------------------------------------------
00176 KDE_EXPORT bool kBytesToFile(const char* aBuffer, int len,
00177            const QString &aFileName,
00178            bool aAskIfExists, bool aBackup, bool aVerbose)
00179 {
00180   // TODO: use KSaveFile
00181   QFile file(aFileName);
00182   int writeLen, rc;
00183 
00184   //assert(aFileName!=0);
00185   if(aFileName.isEmpty())
00186     return FALSE;
00187 
00188   if (file.exists())
00189   {
00190     if (aAskIfExists)
00191     {
00192       QString str;
00193       str = i18n("File %1 exists.\nDo you want to replace it?")
00194           .arg(aFileName);
00195       rc = KMessageBox::warningContinueCancel(0,
00196        str, i18n("Save to File"), i18n("&Replace"));
00197       if (rc != KMessageBox::Continue) return FALSE;
00198     }
00199     if (aBackup)
00200     {
00201       // make a backup copy
00202       // TODO: use KSaveFile::backupFile()
00203       QString bakName = aFileName;
00204       bakName += '~';
00205       QFile::remove(bakName);
00206       if( !QDir::current().rename(aFileName, bakName) )
00207       {
00208     // failed to rename file
00209     if (!aVerbose) return FALSE;
00210     rc = KMessageBox::warningContinueCancel(0,
00211          i18n("Failed to make a backup copy of %1.\nContinue anyway?")
00212          .arg(aFileName),
00213              i18n("Save to File"), KStdGuiItem::save() );
00214     if (rc != KMessageBox::Continue) return FALSE;
00215       }
00216     }
00217   }
00218 
00219   if (!file.open(IO_Raw|IO_WriteOnly|IO_Truncate))
00220   {
00221     if (aVerbose) switch(file.status())
00222     {
00223     case IO_WriteError:
00224       msgDialog(i18n("Could not write to file:\n%1").arg(aFileName));
00225       break;
00226     case IO_OpenError:
00227       msgDialog(i18n("Could not open file for writing:\n%1")
00228         .arg(aFileName));
00229       break;
00230     default:
00231       msgDialog(i18n("Error while writing file:\n%1").arg(aFileName));
00232     }
00233     return FALSE;
00234   }
00235 
00236   writeLen = file.writeBlock(aBuffer, len);
00237 
00238   if (writeLen < 0)
00239   {
00240     if (aVerbose)
00241       msgDialog(i18n("Could not write to file:\n%1").arg(aFileName));
00242     return FALSE;
00243   }
00244   else if (writeLen < len)
00245   {
00246     QString msg = i18n("Could only write %1 bytes of %2.")
00247         .arg(writeLen).arg(len);
00248     if (aVerbose)
00249       msgDialog(msg);
00250     return FALSE;
00251   }
00252 
00253   return TRUE;
00254 }
00255 
00256 KDE_EXPORT bool kCStringToFile(const QCString& aBuffer, const QString &aFileName,
00257            bool aAskIfExists, bool aBackup, bool aVerbose)
00258 {
00259     return kBytesToFile(aBuffer, aBuffer.length(), aFileName, aAskIfExists,
00260     aBackup, aVerbose);
00261 }
00262 
00263 KDE_EXPORT bool kByteArrayToFile(const QByteArray& aBuffer, const QString &aFileName,
00264            bool aAskIfExists, bool aBackup, bool aVerbose)
00265 {
00266     return kBytesToFile(aBuffer, aBuffer.size(), aFileName, aAskIfExists,
00267     aBackup, aVerbose);
00268 }
00269 
00270 
00271 QString checkAndCorrectPermissionsIfPossible( const QString &toCheck,
00272   const bool recursive, const bool wantItReadable,
00273   const bool wantItWritable )
00274 {
00275   // First we have to find out which type the toCheck is. This can be
00276   // a directory (follow if recursive) or a file (check permissions).
00277   // Symlinks are followed as expected.
00278   QFileInfo fiToCheck(toCheck);
00279   fiToCheck.setCaching(false);
00280   QCString toCheckEnc = QFile::encodeName(toCheck);
00281   QString error;
00282   struct stat statbuffer;
00283 
00284   if ( !fiToCheck.exists() ) {
00285     error.append( i18n("%1 does not exist")
00286                   .arg(toCheck) + "\n");
00287   }
00288 
00289   // check the access bit of a folder.
00290   if ( fiToCheck.isDir() ) {
00291     if ( stat( toCheckEnc,&statbuffer ) != 0 ) {
00292       kdDebug() << "wantItA: Can't read perms of " << toCheck << endl;
00293     }
00294     QDir g( toCheck );
00295     if ( !g.isReadable() ) {
00296       if ( chmod( toCheckEnc, statbuffer.st_mode + S_IXUSR ) != 0 ) {
00297         error.append( i18n("%1 is not accessible and that is "
00298                            "unchangeable.").arg(toCheck) + "\n");
00299       } else {
00300         kdDebug() << "Changed access bit for " << toCheck << endl;
00301       }
00302     }
00303   }
00304 
00305   // For each file or folder  we can check if the file is readable 
00306   // and writable, as requested.
00307   if ( fiToCheck.isFile() || fiToCheck.isDir() ) {
00308 
00309     if ( !fiToCheck.isReadable() && wantItReadable ) {
00310       // Get the current permissions. No need to do anything with an 
00311       // error, it will het added to errors anyhow, later on.
00312       if ( stat(toCheckEnc,&statbuffer) != 0 ) {
00313         kdDebug() << "wantItR: Can't read perms of " << toCheck << endl;
00314       }
00315 
00316       // Lets try changing it.
00317       if ( chmod( toCheckEnc, statbuffer.st_mode + S_IRUSR ) != 0 ) {
00318         error.append( i18n("%1 is not readable and that is unchangeable.")
00319                            .arg(toCheck) + "\n");
00320       } else {
00321         kdDebug() << "Changed the read bit for " << toCheck << endl;
00322       }
00323     }
00324 
00325     if ( !fiToCheck.isWritable() && wantItWritable ) {
00326       // Gets the current persmissions. Needed because it can be changed
00327       // curing previous operation.
00328       if (stat(toCheckEnc,&statbuffer) != 0) {
00329         kdDebug() << "wantItW: Can't read perms of " << toCheck << endl;
00330       }
00331 
00332       // Lets try changing it.
00333       if ( chmod (toCheckEnc, statbuffer.st_mode + S_IWUSR ) != 0 ) {
00334         error.append( i18n("%1 is not writable and that is unchangeable.")
00335                            .arg(toCheck) + "\n");
00336       } else {
00337         kdDebug() << "Changed the write bit for " << toCheck << endl;
00338       }
00339     }
00340   }
00341 
00342   // If it is a folder and recursive is true, then we check the contents of 
00343   // the folder.
00344   if ( fiToCheck.isDir() && recursive ){
00345     QDir g(toCheck);
00346     // First check if the folder is readable for us. If not, we get
00347     // some ugly crashes.
00348     if ( !g.isReadable() ){
00349       error.append(i18n("Folder %1 is inaccessible.").arg(toCheck) + "\n");
00350     } else {
00351       const QFileInfoList *list = g.entryInfoList();
00352       QFileInfoListIterator it( *list );
00353       QFileInfo *fi;
00354       while ((fi = it.current()) != 0) {
00355         QString newToCheck = toCheck + "/" + fi->fileName();
00356         QFileInfo fiNewToCheck(newToCheck);
00357         if ( fi->fileName() != "." && fi->fileName() != ".." ) {
00358           error.append ( checkAndCorrectPermissionsIfPossible( newToCheck, 
00359                                 recursive, wantItReadable, wantItWritable) );
00360         }
00361         ++it;
00362       }
00363     }
00364   }
00365   return error;
00366 }
00367 
00368 bool checkAndCorrectPermissionsIfPossibleWithErrorHandling( QWidget *parent,
00369   const QString &toCheck, const bool recursive, const bool wantItReadable,
00370   const bool wantItWritable )
00371 {
00372   QString error = checkAndCorrectPermissionsIfPossible(toCheck, recursive, 
00373                                            wantItReadable, wantItWritable);
00374   // There is no KMessageBox with Retry, Cancel and Details. 
00375   // so, I can't provide a functionality to recheck. So it now 
00376   // it is just a warning.
00377   if ( !error.isEmpty() ) {
00378     kdDebug() << "checkPermissions found:" << error << endl;
00379     KMessageBox::detailedSorry(parent, 
00380                                i18n("Some files or folders do not have "
00381                                "the right permissions, please correct them "
00382                                "manually."),
00383                                error, i18n("Permissions Check"), false);
00384     return false;
00385   } else {
00386     return true;
00387   }
00388 }
00389 
00390 }
KDE Home | KDE Accessibility Home | Description of Access Keys