// tdefileio.cpp // Author: Stefan Taferner // License: GPL #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include namespace KPIM { //----------------------------------------------------------------------------- static void msgDialog(const TQString &msg) { KMessageBox::sorry(0, msg, i18n("File I/O Error")); } //----------------------------------------------------------------------------- KDE_EXPORT TQCString kFileToString(const TQString &aFileName, bool aEnsureNL, bool aVerbose) { TQCString result; TQFileInfo info(aFileName); unsigned int readLen; unsigned int len = info.size(); TQFile file(aFileName); //assert(aFileName!=0); if( aFileName.isEmpty() ) return ""; if (!info.exists()) { if (aVerbose) msgDialog(i18n("The specified file does not exist:\n%1").arg(aFileName)); return TQCString(); } if (info.isDir()) { if (aVerbose) msgDialog(i18n("This is a folder and not a file:\n%1").arg(aFileName)); return TQCString(); } if (!info.isReadable()) { if (aVerbose) msgDialog(i18n("You do not have read permissions " "to the file:\n%1").arg(aFileName)); return TQCString(); } if (len <= 0) return TQCString(); if (!file.open(IO_Raw|IO_ReadOnly)) { if (aVerbose) switch(file.status()) { case IO_ReadError: msgDialog(i18n("Could not read file:\n%1").arg(aFileName)); break; case IO_OpenError: msgDialog(i18n("Could not open file:\n%1").arg(aFileName)); break; default: msgDialog(i18n("Error while reading file:\n%1").arg(aFileName)); } return TQCString(); } result.resize(len + (int)aEnsureNL + 1); readLen = file.readBlock(result.data(), len); if (aEnsureNL && result[len-1]!='\n') { result[len++] = '\n'; readLen++; } result[len] = '\0'; if (readLen < len) { TQString msg = i18n("Could only read %1 bytes of %2.") .arg(readLen).arg(len); msgDialog(msg); return TQCString(); } return result; } //----------------------------------------------------------------------------- #if 0 // unused TQByteArray kFileToBytes(const TQString &aFileName, bool aVerbose) { TQByteArray result; TQFileInfo info(aFileName); unsigned int readLen; unsigned int len = info.size(); TQFile file(aFileName); //assert(aFileName!=0); if( aFileName.isEmpty() ) return result; if (!info.exists()) { if (aVerbose) msgDialog(i18n("The specified file does not exist:\n%1") .arg(aFileName)); return result; } if (info.isDir()) { if (aVerbose) msgDialog(i18n("This is a folder and not a file:\n%1") .arg(aFileName)); return result; } if (!info.isReadable()) { if (aVerbose) msgDialog(i18n("You do not have read permissions " "to the file:\n%1").arg(aFileName)); return result; } if (len <= 0) return result; if (!file.open(IO_Raw|IO_ReadOnly)) { if (aVerbose) switch(file.status()) { case IO_ReadError: msgDialog(i18n("Could not read file:\n%1").arg(aFileName)); break; case IO_OpenError: msgDialog(i18n("Could not open file:\n%1").arg(aFileName)); break; default: msgDialog(i18n("Error while reading file:\n%1").arg(aFileName)); } return result; } result.resize(len); readLen = file.readBlock(result.data(), len); kdDebug(5300) << TQString( "len %1" ).arg(len) << endl; if (readLen < len) { TQString msg; msg = i18n("Could only read %1 bytes of %2.") .arg(readLen).arg(len); msgDialog(msg); return result; } return result; } #endif //----------------------------------------------------------------------------- KDE_EXPORT bool kBytesToFile(const char* aBuffer, int len, const TQString &aFileName, bool aAskIfExists, bool aBackup, bool aVerbose) { // TODO: use KSaveFile TQFile file(aFileName); int writeLen, rc; //assert(aFileName!=0); if(aFileName.isEmpty()) return FALSE; if (file.exists()) { if (aAskIfExists) { TQString str; str = i18n("File %1 exists.\nDo you want to replace it?") .arg(aFileName); rc = KMessageBox::warningContinueCancel(0, str, i18n("Save to File"), i18n("&Replace")); if (rc != KMessageBox::Continue) return FALSE; } if (aBackup) { // make a backup copy // TODO: use KSaveFile::backupFile() TQString bakName = aFileName; bakName += '~'; TQFile::remove(bakName); if( !TQDir::current().rename(aFileName, bakName) ) { // failed to rename file if (!aVerbose) return FALSE; rc = KMessageBox::warningContinueCancel(0, i18n("Failed to make a backup copy of %1.\nContinue anyway?") .arg(aFileName), i18n("Save to File"), KStdGuiItem::save() ); if (rc != KMessageBox::Continue) return FALSE; } } } if (!file.open(IO_Raw|IO_WriteOnly|IO_Truncate)) { if (aVerbose) switch(file.status()) { case IO_WriteError: msgDialog(i18n("Could not write to file:\n%1").arg(aFileName)); break; case IO_OpenError: msgDialog(i18n("Could not open file for writing:\n%1") .arg(aFileName)); break; default: msgDialog(i18n("Error while writing file:\n%1").arg(aFileName)); } return FALSE; } writeLen = file.writeBlock(aBuffer, len); if (writeLen < 0) { if (aVerbose) msgDialog(i18n("Could not write to file:\n%1").arg(aFileName)); return FALSE; } else if (writeLen < len) { TQString msg = i18n("Could only write %1 bytes of %2.") .arg(writeLen).arg(len); if (aVerbose) msgDialog(msg); return FALSE; } return TRUE; } KDE_EXPORT bool kCStringToFile(const TQCString& aBuffer, const TQString &aFileName, bool aAskIfExists, bool aBackup, bool aVerbose) { return kBytesToFile(aBuffer, aBuffer.length(), aFileName, aAskIfExists, aBackup, aVerbose); } KDE_EXPORT bool kByteArrayToFile(const TQByteArray& aBuffer, const TQString &aFileName, bool aAskIfExists, bool aBackup, bool aVerbose) { return kBytesToFile(aBuffer, aBuffer.size(), aFileName, aAskIfExists, aBackup, aVerbose); } TQString checkAndCorrectPermissionsIfPossible( const TQString &toCheck, const bool recursive, const bool wantItReadable, const bool wantItWritable ) { // First we have to find out which type the toCheck is. This can be // a directory (follow if recursive) or a file (check permissions). // Symlinks are followed as expected. TQFileInfo fiToCheck(toCheck); fiToCheck.setCaching(false); TQCString toCheckEnc = TQFile::encodeName(toCheck); TQString error; struct stat statbuffer; if ( !fiToCheck.exists() ) { error.append( i18n("%1 does not exist") .arg(toCheck) + "\n"); } // check the access bit of a folder. if ( fiToCheck.isDir() ) { if ( stat( toCheckEnc,&statbuffer ) != 0 ) { kdDebug() << "wantItA: Can't read perms of " << toCheck << endl; } TQDir g( toCheck ); if ( !g.isReadable() ) { if ( chmod( toCheckEnc, statbuffer.st_mode + S_IXUSR ) != 0 ) { error.append( i18n("%1 is not accessible and that is " "unchangeable.").arg(toCheck) + "\n"); } else { kdDebug() << "Changed access bit for " << toCheck << endl; } } } // For each file or folder we can check if the file is readable // and writable, as requested. if ( fiToCheck.isFile() || fiToCheck.isDir() ) { if ( !fiToCheck.isReadable() && wantItReadable ) { // Get the current permissions. No need to do anything with an // error, it will het added to errors anyhow, later on. if ( stat(toCheckEnc,&statbuffer) != 0 ) { kdDebug() << "wantItR: Can't read perms of " << toCheck << endl; } // Lets try changing it. if ( chmod( toCheckEnc, statbuffer.st_mode + S_IRUSR ) != 0 ) { error.append( i18n("%1 is not readable and that is unchangeable.") .arg(toCheck) + "\n"); } else { kdDebug() << "Changed the read bit for " << toCheck << endl; } } if ( !fiToCheck.isWritable() && wantItWritable ) { // Gets the current persmissions. Needed because it can be changed // curing previous operation. if (stat(toCheckEnc,&statbuffer) != 0) { kdDebug() << "wantItW: Can't read perms of " << toCheck << endl; } // Lets try changing it. if ( chmod (toCheckEnc, statbuffer.st_mode + S_IWUSR ) != 0 ) { error.append( i18n("%1 is not writable and that is unchangeable.") .arg(toCheck) + "\n"); } else { kdDebug() << "Changed the write bit for " << toCheck << endl; } } } // If it is a folder and recursive is true, then we check the contents of // the folder. if ( fiToCheck.isDir() && recursive ){ TQDir g(toCheck); // First check if the folder is readable for us. If not, we get // some ugly crashes. if ( !g.isReadable() ){ error.append(i18n("Folder %1 is inaccessible.").arg(toCheck) + "\n"); } else { const TQFileInfoList *list = g.entryInfoList(); TQFileInfoListIterator it( *list ); TQFileInfo *fi; while ((fi = it.current()) != 0) { TQString newToCheck = toCheck + "/" + fi->fileName(); TQFileInfo fiNewToCheck(newToCheck); if ( fi->fileName() != "." && fi->fileName() != ".." ) { error.append ( checkAndCorrectPermissionsIfPossible( newToCheck, recursive, wantItReadable, wantItWritable) ); } ++it; } } } return error; } bool checkAndCorrectPermissionsIfPossibleWithErrorHandling( TQWidget *parent, const TQString &toCheck, const bool recursive, const bool wantItReadable, const bool wantItWritable ) { TQString error = checkAndCorrectPermissionsIfPossible(toCheck, recursive, wantItReadable, wantItWritable); // There is no KMessageBox with Retry, Cancel and Details. // so, I can't provide a functionality to recheck. So it now // it is just a warning. if ( !error.isEmpty() ) { kdDebug() << "checkPermissions found:" << error << endl; KMessageBox::detailedSorry(parent, i18n("Some files or folders do not have " "the right permissions, please correct them " "manually."), error, i18n("Permissions Check"), false); return false; } else { return true; } } }