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