00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <unistd.h>
00025 #include <ctype.h>
00026 #ifdef HAVE_SYS_MMAN_H
00027 #include <sys/mman.h>
00028 #endif
00029 #include <sys/types.h>
00030 #ifdef HAVE_SYS_STAT_H
00031 #include <sys/stat.h>
00032 #endif
00033 #include <fcntl.h>
00034 #include <signal.h>
00035 #include <setjmp.h>
00036
00037 #include <qdir.h>
00038 #include <qfileinfo.h>
00039 #include <qtextcodec.h>
00040 #include <qtextstream.h>
00041
00042 #include "kconfigbackend.h"
00043 #include "kconfigbase.h"
00044 #include <kapplication.h>
00045 #include <kglobal.h>
00046 #include <kprocess.h>
00047 #include <klocale.h>
00048 #include <kstandarddirs.h>
00049 #include <ksavefile.h>
00050 #include <kurl.h>
00051
00052 extern bool checkAccess(const QString& pathname, int mode);
00053
00054 static QCString printableToString(const char *str, int l)
00055 {
00056
00057 while((l>0) &&
00058 ((*str == ' ') || (*str == '\t') || (*str == '\r')))
00059 {
00060 str++; l--;
00061 }
00062
00063
00064 while((l>0) &&
00065 ((str[l-1] == ' ') || (str[l-1] == '\t') || (str[l-1] == '\r')))
00066 {
00067 l--;
00068 }
00069
00070 QCString result(l + 1);
00071 char *r = result.data();
00072
00073 for(int i = 0; i < l;i++, str++)
00074 {
00075 if (*str == '\\')
00076 {
00077 i++, str++;
00078 if (i >= l)
00079 {
00080 *r++ = '\\';
00081 break;
00082 }
00083 switch(*str)
00084 {
00085 case 's':
00086 *r++ = ' ';
00087 break;
00088 case 't':
00089 *r++ = '\t';
00090 break;
00091 case 'n':
00092 *r++ = '\n';
00093 break;
00094 case 'r':
00095 *r++ = '\r';
00096 break;
00097 case '\\':
00098 *r++ = '\\';
00099 break;
00100 default:
00101 *r++ = '\\';
00102 *r++ = *str;
00103 }
00104 }
00105 else
00106 {
00107 *r++ = *str;
00108 }
00109 }
00110 result.truncate(r-result.data());
00111 return result;
00112 }
00113
00114 static QCString stringToPrintable(const QCString& str){
00115 QCString result(str.length()*2);
00116 register char *r = result.data();
00117 register char *s = str.data();
00118
00119 if (!s) return QCString("");
00120
00121
00122 if (*s == ' ')
00123 {
00124 *r++ = '\\'; *r++ = 's';
00125 s++;
00126 }
00127
00128 if (*s)
00129 {
00130 while(*s)
00131 {
00132 if (*s == '\n')
00133 {
00134 *r++ = '\\'; *r++ = 'n';
00135 }
00136 else if (*s == '\t')
00137 {
00138 *r++ = '\\'; *r++ = 't';
00139 }
00140 else if (*s == '\r')
00141 {
00142 *r++ = '\\'; *r++ = 'r';
00143 }
00144 else if (*s == '\\')
00145 {
00146 *r++ = '\\'; *r++ = '\\';
00147 }
00148 else
00149 {
00150 *r++ = *s;
00151 }
00152 s++;
00153 }
00154
00155 if (*(r-1) == ' ')
00156 {
00157 *(r-1) = '\\'; *r++ = 's';
00158 }
00159 }
00160
00161 result.truncate(r - result.data());
00162 return result;
00163 }
00164
00165 static QCString decodeGroup(const char*s, int l)
00166 {
00167 QCString result(l);
00168 register char *r = result.data();
00169
00170 l--;
00171 while(l)
00172 {
00173 if ((*s == '[') && (l > 1))
00174 {
00175 if ((*(s+1) == '['))
00176 {
00177 l--;
00178 s++;
00179 }
00180 }
00181 if ((*s == ']') && (l > 1))
00182 {
00183 if ((*(s+1) == ']'))
00184 {
00185 l--;
00186 s++;
00187 }
00188 }
00189 *r++ = *s++;
00190 l--;
00191 }
00192 result.truncate(r - result.data());
00193 return result;
00194 }
00195
00196 static QCString encodeGroup(const QCString &str)
00197 {
00198 int l = str.length();
00199 QCString result(l*2+1);
00200 register char *r = result.data();
00201 register char *s = str.data();
00202 while(l)
00203 {
00204 if ((*s == '[') || (*s == ']'))
00205 *r++ = *s;
00206 *r++ = *s++;
00207 l--;
00208 }
00209 result.truncate(r - result.data());
00210 return result;
00211 }
00212
00213 class KConfigBackEnd::KConfigBackEndPrivate
00214 {
00215 public:
00216 QDateTime localLastModified;
00217 uint localLastSize;
00218 };
00219
00220 void KConfigBackEnd::changeFileName(const QString &_fileName,
00221 const char * _resType,
00222 bool _useKDEGlobals)
00223 {
00224 mfileName = _fileName;
00225 resType = _resType;
00226 useKDEGlobals = _useKDEGlobals;
00227 if (mfileName.isEmpty())
00228 mLocalFileName = QString::null;
00229 else if (mfileName[0] == '/')
00230 mLocalFileName = mfileName;
00231 else
00232 mLocalFileName = KGlobal::dirs()->saveLocation(resType) + mfileName;
00233
00234 if (useKDEGlobals)
00235 mGlobalFileName = KGlobal::dirs()->saveLocation("config") +
00236 QString::fromLatin1("kdeglobals");
00237 else
00238 mGlobalFileName = QString::null;
00239
00240 d->localLastModified = QDateTime();
00241 d->localLastSize = 0;
00242 }
00243
00244 KConfigBackEnd::KConfigBackEnd(KConfigBase *_config,
00245 const QString &_fileName,
00246 const char * _resType,
00247 bool _useKDEGlobals)
00248 : pConfig(_config), bFileImmutable(false), mConfigState(KConfigBase::NoAccess), mFileMode(-1)
00249 {
00250 d = new KConfigBackEndPrivate;
00251 changeFileName(_fileName, _resType, _useKDEGlobals);
00252 }
00253
00254 KConfigBackEnd::~KConfigBackEnd()
00255 {
00256 delete d;
00257 }
00258
00259 void KConfigBackEnd::setFileWriteMode(int mode)
00260 {
00261 mFileMode = mode;
00262 }
00263
00264 bool KConfigINIBackEnd::parseConfigFiles()
00265 {
00266
00267 mConfigState = KConfigBase::ReadOnly;
00268 if (!mLocalFileName.isEmpty() && !pConfig->isReadOnly())
00269 {
00270 if (checkAccess(mLocalFileName, W_OK))
00271 {
00272 mConfigState = KConfigBase::ReadWrite;
00273 }
00274 else
00275 {
00276
00277 KURL path;
00278 path.setPath(mLocalFileName);
00279 QString dir=path.directory();
00280 KStandardDirs::makeDir(dir);
00281
00282 if (checkAccess(mLocalFileName, W_OK))
00283 {
00284 mConfigState = KConfigBase::ReadWrite;
00285 }
00286 }
00287 QFileInfo info(mLocalFileName);
00288 d->localLastModified = info.lastModified();
00289 d->localLastSize = info.size();
00290 }
00291
00292
00293 bFileImmutable = false;
00294
00295
00296 if (useKDEGlobals) {
00297 QStringList kdercs = KGlobal::dirs()->
00298 findAllResources("config", QString::fromLatin1("kdeglobals"));
00299
00300 if (checkAccess(QString::fromLatin1("/etc/kderc"), R_OK))
00301 kdercs += QString::fromLatin1("/etc/kderc");
00302
00303 kdercs += KGlobal::dirs()->
00304 findAllResources("config", QString::fromLatin1("system.kdeglobals"));
00305
00306 QStringList::ConstIterator it;
00307
00308 for (it = kdercs.fromLast(); it != kdercs.end(); --it) {
00309
00310 QFile aConfigFile( *it );
00311 if (!aConfigFile.open( IO_ReadOnly ))
00312 continue;
00313 parseSingleConfigFile( aConfigFile, 0L, true, (*it != mGlobalFileName) );
00314 aConfigFile.close();
00315 if (bFileImmutable)
00316 break;
00317 }
00318 }
00319
00320 bool bReadFile = !mfileName.isEmpty();
00321 while(bReadFile) {
00322 bReadFile = false;
00323 QString bootLanguage;
00324 if (useKDEGlobals && localeString.isEmpty() && !KGlobal::_locale) {
00325
00326 bootLanguage = KLocale::_initLanguage(pConfig);
00327 setLocaleString(bootLanguage.utf8());
00328 }
00329
00330 bFileImmutable = false;
00331 QStringList list;
00332 if ( mfileName[0] == '/' )
00333 list << mfileName;
00334 else
00335 list = KGlobal::dirs()->findAllResources(resType, mfileName);
00336
00337 QStringList::ConstIterator it;
00338
00339 for (it = list.fromLast(); it != list.end(); --it) {
00340
00341 QFile aConfigFile( *it );
00342
00343 bool bIsLocal = (*it == mLocalFileName);
00344 if (aConfigFile.open( IO_ReadOnly )) {
00345 parseSingleConfigFile( aConfigFile, 0L, false, !bIsLocal );
00346 aConfigFile.close();
00347 if (bFileImmutable)
00348 break;
00349 }
00350 }
00351 if (KGlobal::dirs()->isRestrictedResource(resType, mfileName))
00352 bFileImmutable = true;
00353 QString currentLanguage;
00354 if (!bootLanguage.isEmpty())
00355 {
00356 currentLanguage = KLocale::_initLanguage(pConfig);
00357
00358
00359 if (bootLanguage != currentLanguage)
00360 {
00361 bReadFile = true;
00362 setLocaleString(currentLanguage.utf8());
00363 }
00364 }
00365 }
00366 if (bFileImmutable)
00367 mConfigState = KConfigBase::ReadOnly;
00368
00369 return true;
00370 }
00371
00372 #ifdef HAVE_MMAP
00373 #ifdef SIGBUS
00374 static sigjmp_buf mmap_jmpbuf;
00375 struct sigaction mmap_old_sigact;
00376
00377 extern "C" {
00378 static void mmap_sigbus_handler(int)
00379 {
00380 siglongjmp (mmap_jmpbuf, 1);
00381 }
00382 }
00383 #endif
00384 #endif
00385
00386 extern bool kde_kiosk_exception;
00387
00388 void KConfigINIBackEnd::parseSingleConfigFile(QFile &rFile,
00389 KEntryMap *pWriteBackMap,
00390 bool bGlobal, bool bDefault)
00391 {
00392 const char *s;
00393 const char *eof;
00394 QByteArray data;
00395
00396 if (!rFile.isOpen())
00397 return;
00398
00399
00400
00401
00402
00403
00404 QCString aCurrentGroup("<default>");
00405
00406 unsigned int ll = localeString.length();
00407
00408 #ifdef HAVE_MMAP
00409 static volatile const char *map;
00410 map = ( const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
00411 rFile.handle(), 0);
00412
00413 if (map)
00414 {
00415 s = (const char*) map;
00416 eof = s + rFile.size();
00417
00418 #ifdef SIGBUS
00419 struct sigaction act;
00420 act.sa_handler = mmap_sigbus_handler;
00421 sigemptyset( &act.sa_mask );
00422 #ifdef SA_ONESHOT
00423 act.sa_flags = SA_ONESHOT;
00424 #else
00425 act.sa_flags = SA_RESETHAND;
00426 #endif
00427 sigaction( SIGBUS, &act, &mmap_old_sigact );
00428
00429 if (sigsetjmp (mmap_jmpbuf, 1))
00430 {
00431 munmap(( char* )map, rFile.size());
00432 sigaction (SIGBUS, &mmap_old_sigact, 0);
00433 return;
00434 }
00435 #endif
00436 }
00437 else
00438 #endif
00439 {
00440 rFile.at(0);
00441 data = rFile.readAll();
00442 s = data.data();
00443 eof = s + data.size();
00444 }
00445
00446 bool fileOptionImmutable = false;
00447 bool groupOptionImmutable = false;
00448 bool groupSkip = false;
00449
00450 int line = 0;
00451 for(; s < eof; s++)
00452 {
00453 line++;
00454
00455 while((s < eof) && isspace(*s) && (*s != '\n'))
00456 s++;
00457
00458
00459 if ((s < eof) && ((*s == '\n') || (*s == '#')))
00460 {
00461 sktoeol:
00462 while ((s < eof) && (*s != '\n'))
00463 s++;
00464 continue;
00465 }
00466 const char *startLine = s;
00467
00468 if (*s == '[')
00469 {
00470
00471 while ((s < eof) && (*s != '\n'))
00472 {
00473 if (*s == ']')
00474 {
00475 if ((s+1 < eof) && (*(s+1) == ']'))
00476 s++;
00477 else
00478 break;
00479 }
00480
00481 s++;
00482 }
00483 const char *e = s;
00484 while ((s < eof) && (*s != '\n')) s++;
00485 if ((e >= eof) || (*e != ']'))
00486 {
00487 fprintf(stderr, "Invalid group header at %s:%d\n", rFile.name().latin1(), line);
00488 continue;
00489 }
00490
00491
00492 if ((e-startLine == 3) &&
00493 (startLine[1] == '$') &&
00494 (startLine[2] == 'i'))
00495 {
00496 if (!kde_kiosk_exception)
00497 fileOptionImmutable = true;
00498 continue;
00499 }
00500
00501 aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
00502
00503
00504
00505 if (aCurrentGroup == "KDE Desktop Entry")
00506 aCurrentGroup = "Desktop Entry";
00507
00508 groupOptionImmutable = fileOptionImmutable;
00509
00510 e++;
00511 if ((e+2 < eof) && (*e++ == '[') && (*e++ == '$'))
00512 {
00513 if ((*e == 'i') && !kde_kiosk_exception)
00514 {
00515 groupOptionImmutable = true;
00516 }
00517 }
00518
00519 KEntryKey groupKey(aCurrentGroup, 0);
00520 KEntry entry = pConfig->lookupData(groupKey);
00521 groupSkip = entry.bImmutable;
00522
00523 if (groupSkip && !bDefault)
00524 continue;
00525
00526 entry.bImmutable |= groupOptionImmutable;
00527 pConfig->putData(groupKey, entry, false);
00528
00529 if (pWriteBackMap)
00530 {
00531
00532 (*pWriteBackMap)[groupKey] = entry;
00533 }
00534
00535 continue;
00536 }
00537 if (groupSkip && !bDefault)
00538 goto sktoeol;
00539
00540 bool optionImmutable = groupOptionImmutable;
00541 bool optionDeleted = false;
00542 bool optionExpand = false;
00543 const char *endOfKey = 0, *locale = 0, *elocale = 0;
00544 for (; (s < eof) && (*s != '\n'); s++)
00545 {
00546 if (*s == '=')
00547 {
00548 if (!endOfKey)
00549 endOfKey = s;
00550 goto haveeq;
00551 }
00552 if (*s == '[')
00553 {
00554 const char *option;
00555 const char *eoption;
00556 endOfKey = s;
00557 option = ++s;
00558 for (;; s++)
00559 {
00560 if ((s >= eof) || (*s == '\n') || (*s == '=')) {
00561 fprintf(stderr, "Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
00562 goto sktoeol;
00563 }
00564 if (*s == ']')
00565 break;
00566 }
00567 eoption = s;
00568 if (*option != '$')
00569 {
00570
00571 if (locale) {
00572 fprintf(stderr, "Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
00573 goto sktoeol;
00574 }
00575 locale = option;
00576 elocale = eoption;
00577 }
00578 else
00579 {
00580
00581 while (option < eoption)
00582 {
00583 option++;
00584 if ((*option == 'i') && !kde_kiosk_exception)
00585 optionImmutable = true;
00586 else if (*option == 'e')
00587 optionExpand = true;
00588 else if (*option == 'd')
00589 {
00590 optionDeleted = true;
00591 goto haveeq;
00592 }
00593 else if (*option == ']')
00594 break;
00595 }
00596 }
00597 }
00598 }
00599 fprintf(stderr, "Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
00600 continue;
00601
00602 haveeq:
00603 for (endOfKey--; ; endOfKey--)
00604 {
00605 if (endOfKey < startLine)
00606 {
00607 fprintf(stderr, "Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
00608 goto sktoeol;
00609 }
00610 if (!isspace(*endOfKey))
00611 break;
00612 }
00613
00614 const char *st = ++s;
00615 while ((s < eof) && (*s != '\n')) s++;
00616
00617 if (locale) {
00618 unsigned int cl = static_cast<unsigned int>(elocale - locale);
00619 if ((ll != cl) || memcmp(locale, localeString.data(), ll))
00620 {
00621
00622 if ( cl != 1 || ll != 5 || *locale != 'C' || memcmp(localeString.data(), "en_US", 5)) {
00623
00624
00625 if (!pWriteBackMap)
00626 continue;
00627
00628 endOfKey = elocale;
00629 locale = 0;
00630 }
00631 }
00632 }
00633
00634
00635 QCString key(startLine, endOfKey - startLine + 2);
00636 QCString val = printableToString(st, s - st);
00637
00638
00639 KEntryKey aEntryKey(aCurrentGroup, key);
00640 aEntryKey.bLocal = (locale != 0);
00641 aEntryKey.bDefault = bDefault;
00642
00643 KEntry aEntry;
00644 aEntry.mValue = val;
00645 aEntry.bGlobal = bGlobal;
00646 aEntry.bImmutable = optionImmutable;
00647 aEntry.bDeleted = optionDeleted;
00648 aEntry.bExpand = optionExpand;
00649 aEntry.bNLS = (locale != 0);
00650
00651 if (pWriteBackMap) {
00652
00653
00654 pWriteBackMap->insert(aEntryKey, aEntry);
00655 } else {
00656
00657
00658
00659 pConfig->putData(aEntryKey, aEntry, false);
00660 }
00661 }
00662 if (fileOptionImmutable)
00663 bFileImmutable = true;
00664
00665 #ifdef HAVE_MMAP
00666 if (map)
00667 {
00668 munmap(( char* )map, rFile.size());
00669 #ifdef SIGBUS
00670 sigaction (SIGBUS, &mmap_old_sigact, 0);
00671 #endif
00672 }
00673 #endif
00674 }
00675
00676
00677 void KConfigINIBackEnd::sync(bool bMerge)
00678 {
00679
00680 if (!pConfig->isDirty())
00681 return;
00682
00683 bool bEntriesLeft = true;
00684
00685
00686
00687
00688 if (!mfileName.isEmpty()) {
00689
00690 if ((resType!="config") && mLocalFileName[0]=='/')
00691 {
00692 KURL path;
00693 path.setPath(mLocalFileName);
00694 QString dir=path.directory();
00695 KStandardDirs::makeDir(dir);
00696 }
00697
00698
00699
00700
00701
00702 if (checkAccess(mLocalFileName, W_OK)) {
00703
00704
00705 bool mergeLocalFile = bMerge;
00706
00707 if (mergeLocalFile)
00708 {
00709 QFileInfo info(mLocalFileName);
00710 if ((d->localLastSize == info.size()) &&
00711 (d->localLastModified == info.lastModified()))
00712 {
00713
00714 mergeLocalFile = false;
00715 }
00716 else
00717 {
00718
00719 d->localLastModified = QDateTime();
00720 d->localLastSize = 0;
00721 }
00722 }
00723
00724 bEntriesLeft = writeConfigFile( mLocalFileName, false, mergeLocalFile );
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734 if (!mergeLocalFile)
00735 {
00736 QFileInfo info(mLocalFileName);
00737 d->localLastModified = info.lastModified();
00738 d->localLastSize = info.size();
00739 }
00740 }
00741 }
00742
00743
00744
00745
00746 if (bEntriesLeft && useKDEGlobals) {
00747
00748
00749 if (checkAccess ( mGlobalFileName, W_OK )) {
00750 writeConfigFile( mGlobalFileName, true, bMerge );
00751 }
00752 }
00753
00754 }
00755
00756 static void writeEntries(FILE *pStream, const KEntryMap& entryMap, bool defaultGroup, bool &firstEntry, const QCString &localeString)
00757 {
00758
00759 QCString currentGroup;
00760 for (KEntryMapConstIterator aIt = entryMap.begin();
00761 aIt != entryMap.end(); ++aIt)
00762 {
00763 const KEntryKey &key = aIt.key();
00764
00765
00766 if ((key.mGroup != "<default>") == defaultGroup)
00767 continue;
00768
00769
00770 if ((key.bDefault) || key.mKey.isEmpty())
00771 continue;
00772
00773 const KEntry ¤tEntry = *aIt;
00774
00775 KEntryMapConstIterator aTestIt = aIt;
00776 ++aTestIt;
00777 bool hasDefault = (aTestIt != entryMap.end());
00778 if (hasDefault)
00779 {
00780 const KEntryKey &defaultKey = aTestIt.key();
00781 if ((!defaultKey.bDefault) ||
00782 (defaultKey.mKey != key.mKey) ||
00783 (defaultKey.mGroup != key.mGroup) ||
00784 (defaultKey.bLocal != key.bLocal))
00785 hasDefault = false;
00786 }
00787
00788
00789 if (hasDefault)
00790 {
00791
00792 if ((currentEntry.mValue == (*aTestIt).mValue) &&
00793 (currentEntry.bDeleted == (*aTestIt).bDeleted))
00794 continue;
00795 }
00796 else
00797 {
00798
00799 if (currentEntry.bDeleted)
00800 continue;
00801 }
00802
00803 if (!defaultGroup && (currentGroup != key.mGroup)) {
00804 if (!firstEntry)
00805 fprintf(pStream, "\n");
00806 currentGroup = key.mGroup;
00807 fprintf(pStream, "[%s]\n", encodeGroup(currentGroup).data());
00808 }
00809
00810 firstEntry = false;
00811
00812 fputs(key.mKey.data(), pStream);
00813
00814 if ( currentEntry.bNLS )
00815 {
00816 fputc('[', pStream);
00817 fputs(localeString.data(), pStream);
00818 fputc(']', pStream);
00819 }
00820
00821 if (currentEntry.bDeleted)
00822 {
00823 fputs("[$d]\n", pStream);
00824 }
00825 else
00826 {
00827 if (currentEntry.bImmutable || currentEntry.bExpand)
00828 {
00829 fputc('[', pStream);
00830 fputc('$', pStream);
00831 if (currentEntry.bImmutable)
00832 fputc('i', pStream);
00833 if (currentEntry.bExpand)
00834 fputc('e', pStream);
00835
00836 fputc(']', pStream);
00837 }
00838 fputc('=', pStream);
00839 fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
00840 fputc('\n', pStream);
00841 }
00842 }
00843 }
00844
00845 bool KConfigINIBackEnd::getEntryMap(KEntryMap &aTempMap, bool bGlobal,
00846 QFile *mergeFile)
00847 {
00848 bool bEntriesLeft = false;
00849 bFileImmutable = false;
00850
00851
00852 if (mergeFile && mergeFile->open(IO_ReadOnly))
00853 {
00854
00855 parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal, false );
00856
00857 if (bFileImmutable)
00858 return bEntriesLeft;
00859 }
00860
00861 KEntryMap aMap = pConfig->internalEntryMap();
00862
00863
00864 for (KEntryMapIterator aIt = aMap.begin();
00865 aIt != aMap.end(); ++aIt)
00866 {
00867 const KEntry ¤tEntry = *aIt;
00868 if(aIt.key().bDefault)
00869 {
00870 aTempMap.replace(aIt.key(), currentEntry);
00871 continue;
00872 }
00873
00874 if (mergeFile && !currentEntry.bDirty)
00875 continue;
00876
00877
00878
00879 if (currentEntry.bGlobal != bGlobal)
00880 {
00881
00882 bEntriesLeft = true;
00883 continue;
00884 }
00885
00886
00887
00888 KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
00889 if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
00890 continue;
00891
00892 aTempMap.insert(aIt.key(), currentEntry, true);
00893 }
00894
00895 return bEntriesLeft;
00896 }
00897
00898
00899 bool KConfigINIBackEnd::writeConfigFile(QString filename, bool bGlobal,
00900 bool bMerge)
00901 {
00902
00903 if (pConfig->isReadOnly())
00904 return true;
00905
00906 KEntryMap aTempMap;
00907 QFile *mergeFile = (bMerge ? new QFile(filename) : 0);
00908 bool bEntriesLeft = getEntryMap(aTempMap, bGlobal, mergeFile);
00909 delete mergeFile;
00910 if (bFileImmutable) return true;
00911
00912
00913
00914
00915
00916 int fileMode = -1;
00917 bool createNew = true;
00918
00919 struct stat buf;
00920 if (lstat(QFile::encodeName(filename), &buf) == 0)
00921 {
00922 if (S_ISLNK(buf.st_mode))
00923 {
00924
00925 if (stat(QFile::encodeName(filename), &buf) == 0)
00926 {
00927
00928 createNew = false;
00929 }
00930 }
00931 else if (buf.st_uid == getuid())
00932 {
00933
00934 fileMode = buf.st_mode & 0777;
00935 }
00936 else
00937 {
00938
00939
00940 createNew = false;
00941 }
00942 }
00943
00944 KSaveFile *pConfigFile = 0;
00945 FILE *pStream = 0;
00946
00947 if (createNew)
00948 {
00949 pConfigFile = new KSaveFile( filename, 0600 );
00950
00951 if (pConfigFile->status() != 0)
00952 {
00953 delete pConfigFile;
00954 return bEntriesLeft;
00955 }
00956
00957 if (!bGlobal && (fileMode == -1))
00958 fileMode = mFileMode;
00959
00960 if (fileMode != -1)
00961 {
00962 fchmod(pConfigFile->handle(), fileMode);
00963 }
00964
00965 pStream = pConfigFile->fstream();
00966 }
00967 else
00968 {
00969
00970
00971 int fd = open( QFile::encodeName(filename), O_WRONLY | O_TRUNC);
00972 if (fd < 0)
00973 return bEntriesLeft;
00974 pStream = fdopen( fd, "w");
00975 if (!pStream)
00976 {
00977 close(fd);
00978 return bEntriesLeft;
00979 }
00980 }
00981
00982 writeEntries(pStream, aTempMap);
00983
00984 if (pConfigFile)
00985 {
00986 bool bEmptyFile = (ftell(pStream) == 0);
00987 if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
00988 {
00989
00990 ::unlink(QFile::encodeName(filename));
00991 pConfigFile->abort();
00992 }
00993 else
00994 {
00995
00996 pConfigFile->close();
00997 }
00998 delete pConfigFile;
00999 }
01000 else
01001 {
01002 fclose(pStream);
01003 }
01004
01005 return bEntriesLeft;
01006 }
01007
01008 void KConfigINIBackEnd::writeEntries(FILE *pStream, const KEntryMap &aTempMap)
01009 {
01010 bool firstEntry = true;
01011
01012
01013 ::writeEntries(pStream, aTempMap, true, firstEntry, localeString);
01014
01015
01016 ::writeEntries(pStream, aTempMap, false, firstEntry, localeString);
01017 }
01018
01019 void KConfigBackEnd::virtual_hook( int, void* )
01020 { }
01021
01022 void KConfigINIBackEnd::virtual_hook( int id, void* data )
01023 { KConfigBackEnd::virtual_hook( id, data ); }
01024
01025 bool KConfigBackEnd::checkConfigFilesWritable(bool warnUser)
01026 {
01027
01028 bool allWritable = true;
01029 QString errorMsg( i18n("Will not save configuration.\n") );
01030 if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
01031 {
01032 allWritable = false;
01033 errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
01034 }
01035
01036
01037 if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
01038 {
01039 errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
01040 allWritable = false;
01041 }
01042
01043 if (warnUser && !allWritable)
01044 {
01045
01046 errorMsg += i18n("Please contact your system administrator.");
01047 QString cmdToExec = KStandardDirs::findExe(QString("kdialog"));
01048 KApplication *app = kapp;
01049 if (!cmdToExec.isEmpty() && app)
01050 {
01051 KProcess lprocess;
01052 lprocess << cmdToExec << "--title" << app->instanceName() << "--msgbox" << errorMsg.local8Bit();
01053 lprocess.start( KProcess::Block );
01054 }
01055 }
01056 return allWritable;
01057 }