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 KLockFile::Ptr localLockFile;
00219 KLockFile::Ptr globalLockFile;
00220 };
00221
00222 void KConfigBackEnd::changeFileName(const QString &_fileName,
00223 const char * _resType,
00224 bool _useKDEGlobals)
00225 {
00226 mfileName = _fileName;
00227 resType = _resType;
00228 useKDEGlobals = _useKDEGlobals;
00229 if (mfileName.isEmpty())
00230 mLocalFileName = QString::null;
00231 else if (mfileName[0] == '/')
00232 mLocalFileName = mfileName;
00233 else
00234 mLocalFileName = KGlobal::dirs()->saveLocation(resType) + mfileName;
00235
00236 if (useKDEGlobals)
00237 mGlobalFileName = KGlobal::dirs()->saveLocation("config") +
00238 QString::fromLatin1("kdeglobals");
00239 else
00240 mGlobalFileName = QString::null;
00241
00242 d->localLastModified = QDateTime();
00243 d->localLastSize = 0;
00244 d->localLockFile = 0;
00245 d->globalLockFile = 0;
00246 }
00247
00248 KLockFile::Ptr KConfigBackEnd::lockFile(bool bGlobal)
00249 {
00250 if (bGlobal)
00251 {
00252 if (d->globalLockFile)
00253 return d->globalLockFile;
00254
00255 if (!mGlobalFileName.isEmpty())
00256 {
00257 d->globalLockFile = new KLockFile(mGlobalFileName+".lock");
00258 return d->globalLockFile;
00259 }
00260 }
00261 else
00262 {
00263 if (d->localLockFile)
00264 return d->localLockFile;
00265
00266 if (!mLocalFileName.isEmpty())
00267 {
00268 d->localLockFile = new KLockFile(mLocalFileName+".lock");
00269 return d->localLockFile;
00270 }
00271 }
00272 return 0;
00273 }
00274
00275 KConfigBackEnd::KConfigBackEnd(KConfigBase *_config,
00276 const QString &_fileName,
00277 const char * _resType,
00278 bool _useKDEGlobals)
00279 : pConfig(_config), bFileImmutable(false), mConfigState(KConfigBase::NoAccess), mFileMode(-1)
00280 {
00281 d = new KConfigBackEndPrivate;
00282 changeFileName(_fileName, _resType, _useKDEGlobals);
00283 }
00284
00285 KConfigBackEnd::~KConfigBackEnd()
00286 {
00287 delete d;
00288 }
00289
00290 void KConfigBackEnd::setFileWriteMode(int mode)
00291 {
00292 mFileMode = mode;
00293 }
00294
00295 bool KConfigINIBackEnd::parseConfigFiles()
00296 {
00297
00298 mConfigState = KConfigBase::ReadOnly;
00299 if (!mLocalFileName.isEmpty() && !pConfig->isReadOnly())
00300 {
00301 if (checkAccess(mLocalFileName, W_OK))
00302 {
00303 mConfigState = KConfigBase::ReadWrite;
00304 }
00305 else
00306 {
00307
00308 KURL path;
00309 path.setPath(mLocalFileName);
00310 QString dir=path.directory();
00311 KStandardDirs::makeDir(dir);
00312
00313 if (checkAccess(mLocalFileName, W_OK))
00314 {
00315 mConfigState = KConfigBase::ReadWrite;
00316 }
00317 }
00318 QFileInfo info(mLocalFileName);
00319 d->localLastModified = info.lastModified();
00320 d->localLastSize = info.size();
00321 }
00322
00323
00324 bFileImmutable = false;
00325
00326
00327 if (useKDEGlobals) {
00328 QStringList kdercs = KGlobal::dirs()->
00329 findAllResources("config", QString::fromLatin1("kdeglobals"));
00330
00331 if (checkAccess(QString::fromLatin1("/etc/kderc"), R_OK))
00332 kdercs += QString::fromLatin1("/etc/kderc");
00333
00334 kdercs += KGlobal::dirs()->
00335 findAllResources("config", QString::fromLatin1("system.kdeglobals"));
00336
00337 QStringList::ConstIterator it;
00338
00339 for (it = kdercs.fromLast(); it != kdercs.end(); --it) {
00340
00341 QFile aConfigFile( *it );
00342 if (!aConfigFile.open( IO_ReadOnly ))
00343 continue;
00344 parseSingleConfigFile( aConfigFile, 0L, true, (*it != mGlobalFileName) );
00345 aConfigFile.close();
00346 if (bFileImmutable)
00347 break;
00348 }
00349 }
00350
00351 bool bReadFile = !mfileName.isEmpty();
00352 while(bReadFile) {
00353 bReadFile = false;
00354 QString bootLanguage;
00355 if (useKDEGlobals && localeString.isEmpty() && !KGlobal::_locale) {
00356
00357 bootLanguage = KLocale::_initLanguage(pConfig);
00358 setLocaleString(bootLanguage.utf8());
00359 }
00360
00361 bFileImmutable = false;
00362 QStringList list;
00363 if ( mfileName[0] == '/' )
00364 list << mfileName;
00365 else
00366 list = KGlobal::dirs()->findAllResources(resType, mfileName);
00367
00368 QStringList::ConstIterator it;
00369
00370 for (it = list.fromLast(); it != list.end(); --it) {
00371
00372 QFile aConfigFile( *it );
00373
00374 bool bIsLocal = (*it == mLocalFileName);
00375 if (aConfigFile.open( IO_ReadOnly )) {
00376 parseSingleConfigFile( aConfigFile, 0L, false, !bIsLocal );
00377 aConfigFile.close();
00378 if (bFileImmutable)
00379 break;
00380 }
00381 }
00382 if (KGlobal::dirs()->isRestrictedResource(resType, mfileName))
00383 bFileImmutable = true;
00384 QString currentLanguage;
00385 if (!bootLanguage.isEmpty())
00386 {
00387 currentLanguage = KLocale::_initLanguage(pConfig);
00388
00389
00390 if (bootLanguage != currentLanguage)
00391 {
00392 bReadFile = true;
00393 setLocaleString(currentLanguage.utf8());
00394 }
00395 }
00396 }
00397 if (bFileImmutable)
00398 mConfigState = KConfigBase::ReadOnly;
00399
00400 return true;
00401 }
00402
00403 #ifdef HAVE_MMAP
00404 #ifdef SIGBUS
00405 static sigjmp_buf mmap_jmpbuf;
00406 struct sigaction mmap_old_sigact;
00407
00408 extern "C" {
00409 static void mmap_sigbus_handler(int)
00410 {
00411 siglongjmp (mmap_jmpbuf, 1);
00412 }
00413 }
00414 #endif
00415 #endif
00416
00417 extern bool kde_kiosk_exception;
00418
00419 void KConfigINIBackEnd::parseSingleConfigFile(QFile &rFile,
00420 KEntryMap *pWriteBackMap,
00421 bool bGlobal, bool bDefault)
00422 {
00423 const char *s;
00424 const char *eof;
00425 QByteArray data;
00426
00427 if (!rFile.isOpen())
00428 return;
00429
00430
00431
00432
00433
00434
00435 QCString aCurrentGroup("<default>");
00436
00437 unsigned int ll = localeString.length();
00438
00439 #ifdef HAVE_MMAP
00440 static volatile const char *map;
00441 map = ( const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
00442 rFile.handle(), 0);
00443
00444 if (map)
00445 {
00446 s = (const char*) map;
00447 eof = s + rFile.size();
00448
00449 #ifdef SIGBUS
00450 struct sigaction act;
00451 act.sa_handler = mmap_sigbus_handler;
00452 sigemptyset( &act.sa_mask );
00453 #ifdef SA_ONESHOT
00454 act.sa_flags = SA_ONESHOT;
00455 #else
00456 act.sa_flags = SA_RESETHAND;
00457 #endif
00458 sigaction( SIGBUS, &act, &mmap_old_sigact );
00459
00460 if (sigsetjmp (mmap_jmpbuf, 1))
00461 {
00462 qWarning("SIGBUS while reading %s", rFile.name().latin1());
00463 munmap(( char* )map, rFile.size());
00464 sigaction (SIGBUS, &mmap_old_sigact, 0);
00465 return;
00466 }
00467 #endif
00468 }
00469 else
00470 #endif
00471 {
00472 rFile.at(0);
00473 data = rFile.readAll();
00474 s = data.data();
00475 eof = s + data.size();
00476 }
00477
00478 bool fileOptionImmutable = false;
00479 bool groupOptionImmutable = false;
00480 bool groupSkip = false;
00481
00482 int line = 0;
00483 for(; s < eof; s++)
00484 {
00485 line++;
00486
00487 while((s < eof) && isspace(*s) && (*s != '\n'))
00488 s++;
00489
00490
00491 if ((s < eof) && ((*s == '\n') || (*s == '#')))
00492 {
00493 sktoeol:
00494 while ((s < eof) && (*s != '\n'))
00495 s++;
00496 continue;
00497 }
00498 const char *startLine = s;
00499
00500 if (*s == '[')
00501 {
00502
00503 while ((s < eof) && (*s != '\n'))
00504 {
00505 if (*s == ']')
00506 {
00507 if ((s+1 < eof) && (*(s+1) == ']'))
00508 s++;
00509 else
00510 break;
00511 }
00512
00513 s++;
00514 }
00515 const char *e = s;
00516 while ((s < eof) && (*s != '\n')) s++;
00517 if ((e >= eof) || (*e != ']'))
00518 {
00519 fprintf(stderr, "Invalid group header at %s:%d\n", rFile.name().latin1(), line);
00520 continue;
00521 }
00522
00523
00524 if ((e-startLine == 3) &&
00525 (startLine[1] == '$') &&
00526 (startLine[2] == 'i'))
00527 {
00528 if (!kde_kiosk_exception)
00529 fileOptionImmutable = true;
00530 continue;
00531 }
00532
00533 aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
00534
00535
00536
00537 if (aCurrentGroup == "KDE Desktop Entry")
00538 aCurrentGroup = "Desktop Entry";
00539
00540 groupOptionImmutable = fileOptionImmutable;
00541
00542 e++;
00543 if ((e+2 < eof) && (*e++ == '[') && (*e++ == '$'))
00544 {
00545 if ((*e == 'i') && !kde_kiosk_exception)
00546 {
00547 groupOptionImmutable = true;
00548 }
00549 }
00550
00551 KEntryKey groupKey(aCurrentGroup, 0);
00552 KEntry entry = pConfig->lookupData(groupKey);
00553 groupSkip = entry.bImmutable;
00554
00555 if (groupSkip && !bDefault)
00556 continue;
00557
00558 entry.bImmutable |= groupOptionImmutable;
00559 pConfig->putData(groupKey, entry, false);
00560
00561 if (pWriteBackMap)
00562 {
00563
00564 (*pWriteBackMap)[groupKey] = entry;
00565 }
00566
00567 continue;
00568 }
00569 if (groupSkip && !bDefault)
00570 goto sktoeol;
00571
00572 bool optionImmutable = groupOptionImmutable;
00573 bool optionDeleted = false;
00574 bool optionExpand = false;
00575 const char *endOfKey = 0, *locale = 0, *elocale = 0;
00576 for (; (s < eof) && (*s != '\n'); s++)
00577 {
00578 if (*s == '=')
00579 {
00580 if (!endOfKey)
00581 endOfKey = s;
00582 goto haveeq;
00583 }
00584 if (*s == '[')
00585 {
00586 const char *option;
00587 const char *eoption;
00588 endOfKey = s;
00589 option = ++s;
00590 for (;; s++)
00591 {
00592 if ((s >= eof) || (*s == '\n') || (*s == '=')) {
00593 fprintf(stderr, "Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
00594 goto sktoeol;
00595 }
00596 if (*s == ']')
00597 break;
00598 }
00599 eoption = s;
00600 if (*option != '$')
00601 {
00602
00603 if (locale) {
00604 fprintf(stderr, "Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
00605 goto sktoeol;
00606 }
00607 locale = option;
00608 elocale = eoption;
00609 }
00610 else
00611 {
00612
00613 while (option < eoption)
00614 {
00615 option++;
00616 if ((*option == 'i') && !kde_kiosk_exception)
00617 optionImmutable = true;
00618 else if (*option == 'e')
00619 optionExpand = true;
00620 else if (*option == 'd')
00621 {
00622 optionDeleted = true;
00623 goto haveeq;
00624 }
00625 else if (*option == ']')
00626 break;
00627 }
00628 }
00629 }
00630 }
00631 fprintf(stderr, "Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
00632 continue;
00633
00634 haveeq:
00635 for (endOfKey--; ; endOfKey--)
00636 {
00637 if (endOfKey < startLine)
00638 {
00639 fprintf(stderr, "Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
00640 goto sktoeol;
00641 }
00642 if (!isspace(*endOfKey))
00643 break;
00644 }
00645
00646 const char *st = ++s;
00647 while ((s < eof) && (*s != '\n')) s++;
00648
00649 if (locale) {
00650 unsigned int cl = static_cast<unsigned int>(elocale - locale);
00651 if ((ll != cl) || memcmp(locale, localeString.data(), ll))
00652 {
00653
00654 if ( cl != 1 || ll != 5 || *locale != 'C' || memcmp(localeString.data(), "en_US", 5)) {
00655
00656
00657 if (!pWriteBackMap)
00658 continue;
00659
00660 endOfKey = elocale;
00661 locale = 0;
00662 }
00663 }
00664 }
00665
00666
00667 QCString key(startLine, endOfKey - startLine + 2);
00668 QCString val = printableToString(st, s - st);
00669
00670
00671 KEntryKey aEntryKey(aCurrentGroup, key);
00672 aEntryKey.bLocal = (locale != 0);
00673 aEntryKey.bDefault = bDefault;
00674
00675 KEntry aEntry;
00676 aEntry.mValue = val;
00677 aEntry.bGlobal = bGlobal;
00678 aEntry.bImmutable = optionImmutable;
00679 aEntry.bDeleted = optionDeleted;
00680 aEntry.bExpand = optionExpand;
00681 aEntry.bNLS = (locale != 0);
00682
00683 if (pWriteBackMap) {
00684
00685
00686 pWriteBackMap->insert(aEntryKey, aEntry);
00687 } else {
00688
00689
00690
00691 pConfig->putData(aEntryKey, aEntry, false);
00692 }
00693 }
00694 if (fileOptionImmutable)
00695 bFileImmutable = true;
00696
00697 #ifdef HAVE_MMAP
00698 if (map)
00699 {
00700 munmap(( char* )map, rFile.size());
00701 #ifdef SIGBUS
00702 sigaction (SIGBUS, &mmap_old_sigact, 0);
00703 #endif
00704 }
00705 #endif
00706 }
00707
00708
00709 void KConfigINIBackEnd::sync(bool bMerge)
00710 {
00711
00712 if (!pConfig->isDirty())
00713 return;
00714
00715 bool bEntriesLeft = true;
00716
00717
00718
00719
00720 if (!mfileName.isEmpty()) {
00721
00722 if ((resType!="config") && mLocalFileName[0]=='/')
00723 {
00724 KURL path;
00725 path.setPath(mLocalFileName);
00726 QString dir=path.directory();
00727 KStandardDirs::makeDir(dir);
00728 }
00729
00730
00731
00732
00733
00734 if (checkAccess(mLocalFileName, W_OK)) {
00735
00736 KLockFile::Ptr lf;
00737
00738 bool mergeLocalFile = bMerge;
00739
00740 if (mergeLocalFile)
00741 {
00742 lf = lockFile(false);
00743 if (lf && lf->isLocked())
00744 lf = 0;
00745
00746 if (lf)
00747 {
00748 lf->lock( KLockFile::LockForce );
00749
00750 }
00751
00752 QFileInfo info(mLocalFileName);
00753 if ((d->localLastSize == info.size()) &&
00754 (d->localLastModified == info.lastModified()))
00755 {
00756
00757 mergeLocalFile = false;
00758 }
00759 else
00760 {
00761
00762 d->localLastModified = QDateTime();
00763 d->localLastSize = 0;
00764 }
00765 }
00766
00767 bEntriesLeft = writeConfigFile( mLocalFileName, false, mergeLocalFile );
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777 if (!mergeLocalFile)
00778 {
00779 QFileInfo info(mLocalFileName);
00780 d->localLastModified = info.lastModified();
00781 d->localLastSize = info.size();
00782 }
00783 if (lf) lf->unlock();
00784 }
00785 }
00786
00787
00788
00789
00790 if (bEntriesLeft && useKDEGlobals) {
00791
00792
00793 if (checkAccess ( mGlobalFileName, W_OK )) {
00794 KLockFile::Ptr lf = lockFile(true);
00795 if (lf && lf->isLocked())
00796 lf = 0;
00797
00798 if (lf)
00799 {
00800 lf->lock( KLockFile::LockForce );
00801
00802 }
00803 writeConfigFile( mGlobalFileName, true, bMerge );
00804 if (lf) lf->unlock();
00805 }
00806 }
00807
00808 }
00809
00810 static void writeEntries(FILE *pStream, const KEntryMap& entryMap, bool defaultGroup, bool &firstEntry, const QCString &localeString)
00811 {
00812
00813 QCString currentGroup;
00814 for (KEntryMapConstIterator aIt = entryMap.begin();
00815 aIt != entryMap.end(); ++aIt)
00816 {
00817 const KEntryKey &key = aIt.key();
00818
00819
00820 if ((key.mGroup != "<default>") == defaultGroup)
00821 continue;
00822
00823
00824 if ((key.bDefault) || key.mKey.isEmpty())
00825 continue;
00826
00827 const KEntry ¤tEntry = *aIt;
00828
00829 KEntryMapConstIterator aTestIt = aIt;
00830 ++aTestIt;
00831 bool hasDefault = (aTestIt != entryMap.end());
00832 if (hasDefault)
00833 {
00834 const KEntryKey &defaultKey = aTestIt.key();
00835 if ((!defaultKey.bDefault) ||
00836 (defaultKey.mKey != key.mKey) ||
00837 (defaultKey.mGroup != key.mGroup) ||
00838 (defaultKey.bLocal != key.bLocal))
00839 hasDefault = false;
00840 }
00841
00842
00843 if (hasDefault)
00844 {
00845
00846 if ((currentEntry.mValue == (*aTestIt).mValue) &&
00847 (currentEntry.bDeleted == (*aTestIt).bDeleted))
00848 continue;
00849 }
00850 else
00851 {
00852
00853 if (currentEntry.bDeleted)
00854 continue;
00855 }
00856
00857 if (!defaultGroup && (currentGroup != key.mGroup)) {
00858 if (!firstEntry)
00859 fprintf(pStream, "\n");
00860 currentGroup = key.mGroup;
00861 fprintf(pStream, "[%s]\n", encodeGroup(currentGroup).data());
00862 }
00863
00864 firstEntry = false;
00865
00866 fputs(key.mKey.data(), pStream);
00867
00868 if ( currentEntry.bNLS )
00869 {
00870 fputc('[', pStream);
00871 fputs(localeString.data(), pStream);
00872 fputc(']', pStream);
00873 }
00874
00875 if (currentEntry.bDeleted)
00876 {
00877 fputs("[$d]\n", pStream);
00878 }
00879 else
00880 {
00881 if (currentEntry.bImmutable || currentEntry.bExpand)
00882 {
00883 fputc('[', pStream);
00884 fputc('$', pStream);
00885 if (currentEntry.bImmutable)
00886 fputc('i', pStream);
00887 if (currentEntry.bExpand)
00888 fputc('e', pStream);
00889
00890 fputc(']', pStream);
00891 }
00892 fputc('=', pStream);
00893 fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
00894 fputc('\n', pStream);
00895 }
00896 }
00897 }
00898
00899 bool KConfigINIBackEnd::getEntryMap(KEntryMap &aTempMap, bool bGlobal,
00900 QFile *mergeFile)
00901 {
00902 bool bEntriesLeft = false;
00903 bFileImmutable = false;
00904
00905
00906 if (mergeFile && mergeFile->open(IO_ReadOnly))
00907 {
00908
00909 parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal, false );
00910
00911 if (bFileImmutable)
00912 return bEntriesLeft;
00913 }
00914
00915 KEntryMap aMap = pConfig->internalEntryMap();
00916
00917
00918 for (KEntryMapIterator aIt = aMap.begin();
00919 aIt != aMap.end(); ++aIt)
00920 {
00921 const KEntry ¤tEntry = *aIt;
00922 if(aIt.key().bDefault)
00923 {
00924 aTempMap.replace(aIt.key(), currentEntry);
00925 continue;
00926 }
00927
00928 if (mergeFile && !currentEntry.bDirty)
00929 continue;
00930
00931
00932
00933 if (currentEntry.bGlobal != bGlobal)
00934 {
00935
00936 bEntriesLeft = true;
00937 continue;
00938 }
00939
00940
00941
00942 KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
00943 if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
00944 continue;
00945
00946 aTempMap.insert(aIt.key(), currentEntry, true);
00947 }
00948
00949 return bEntriesLeft;
00950 }
00951
00952
00953 bool KConfigINIBackEnd::writeConfigFile(QString filename, bool bGlobal,
00954 bool bMerge)
00955 {
00956
00957 if (pConfig->isReadOnly())
00958 return true;
00959
00960 KEntryMap aTempMap;
00961 QFile *mergeFile = (bMerge ? new QFile(filename) : 0);
00962 bool bEntriesLeft = getEntryMap(aTempMap, bGlobal, mergeFile);
00963 delete mergeFile;
00964 if (bFileImmutable)
00965 return true;
00966
00967
00968
00969
00970
00971 int fileMode = -1;
00972 bool createNew = true;
00973
00974 struct stat buf;
00975 if (stat(QFile::encodeName(filename), &buf) == 0)
00976 {
00977 if (buf.st_uid == getuid())
00978 {
00979
00980 fileMode = buf.st_mode & 0777;
00981 }
00982 else
00983 {
00984
00985
00986 createNew = false;
00987 }
00988 }
00989
00990 KSaveFile *pConfigFile = 0;
00991 FILE *pStream = 0;
00992
00993 if (createNew)
00994 {
00995 pConfigFile = new KSaveFile( filename, 0600 );
00996
00997 if (pConfigFile->status() != 0)
00998 {
00999 delete pConfigFile;
01000 return bEntriesLeft;
01001 }
01002
01003 if (!bGlobal && (fileMode == -1))
01004 fileMode = mFileMode;
01005
01006 if (fileMode != -1)
01007 {
01008 fchmod(pConfigFile->handle(), fileMode);
01009 }
01010
01011 pStream = pConfigFile->fstream();
01012 }
01013 else
01014 {
01015
01016
01017 int fd = open( QFile::encodeName(filename), O_WRONLY | O_TRUNC);
01018 if (fd < 0)
01019 {
01020 return bEntriesLeft;
01021 }
01022 pStream = fdopen( fd, "w");
01023 if (!pStream)
01024 {
01025 close(fd);
01026 return bEntriesLeft;
01027 }
01028 }
01029
01030 writeEntries(pStream, aTempMap);
01031
01032 if (pConfigFile)
01033 {
01034 bool bEmptyFile = (ftell(pStream) == 0);
01035 if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
01036 {
01037
01038 ::unlink(QFile::encodeName(filename));
01039 pConfigFile->abort();
01040 }
01041 else
01042 {
01043
01044 pConfigFile->close();
01045 }
01046 delete pConfigFile;
01047 }
01048 else
01049 {
01050 fclose(pStream);
01051 }
01052
01053 return bEntriesLeft;
01054 }
01055
01056 void KConfigINIBackEnd::writeEntries(FILE *pStream, const KEntryMap &aTempMap)
01057 {
01058 bool firstEntry = true;
01059
01060
01061 ::writeEntries(pStream, aTempMap, true, firstEntry, localeString);
01062
01063
01064 ::writeEntries(pStream, aTempMap, false, firstEntry, localeString);
01065 }
01066
01067 void KConfigBackEnd::virtual_hook( int, void* )
01068 { }
01069
01070 void KConfigINIBackEnd::virtual_hook( int id, void* data )
01071 { KConfigBackEnd::virtual_hook( id, data ); }
01072
01073 bool KConfigBackEnd::checkConfigFilesWritable(bool warnUser)
01074 {
01075
01076 bool allWritable = true;
01077 QString errorMsg( i18n("Will not save configuration.\n") );
01078 if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
01079 {
01080 allWritable = false;
01081 errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
01082 }
01083
01084
01085 if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
01086 {
01087 errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
01088 allWritable = false;
01089 }
01090
01091 if (warnUser && !allWritable)
01092 {
01093
01094 errorMsg += i18n("Please contact your system administrator.");
01095 QString cmdToExec = KStandardDirs::findExe(QString("kdialog"));
01096 KApplication *app = kapp;
01097 if (!cmdToExec.isEmpty() && app)
01098 {
01099 KProcess lprocess;
01100 lprocess << cmdToExec << "--title" << app->instanceName() << "--msgbox" << errorMsg.local8Bit();
01101 lprocess.start( KProcess::Block );
01102 }
01103 }
01104 return allWritable;
01105 }