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 void KConfigINIBackEnd::parseSingleConfigFile(QFile &rFile,
00387 KEntryMap *pWriteBackMap,
00388 bool bGlobal, bool bDefault)
00389 {
00390 const char *s;
00391 const char *eof;
00392 QByteArray data;
00393
00394 if (!rFile.isOpen())
00395 return;
00396
00397
00398
00399
00400
00401
00402 QCString aCurrentGroup("<default>");
00403
00404 unsigned int ll = localeString.length();
00405
00406 #ifdef HAVE_MMAP
00407 static volatile const char *map;
00408 map = ( const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
00409 rFile.handle(), 0);
00410
00411 if (map)
00412 {
00413 s = (const char*) map;
00414 eof = s + rFile.size();
00415
00416 #ifdef SIGBUS
00417 struct sigaction act;
00418 act.sa_handler = mmap_sigbus_handler;
00419 sigemptyset( &act.sa_mask );
00420 #ifdef SA_ONESHOT
00421 act.sa_flags = SA_ONESHOT;
00422 #else
00423 act.sa_flags = SA_RESETHAND;
00424 #endif
00425 sigaction( SIGBUS, &act, &mmap_old_sigact );
00426
00427 if (sigsetjmp (mmap_jmpbuf, 1))
00428 {
00429 munmap(( char* )map, rFile.size());
00430 sigaction (SIGBUS, &mmap_old_sigact, 0);
00431 return;
00432 }
00433 #endif
00434 }
00435 else
00436 #endif
00437 {
00438 rFile.at(0);
00439 data = rFile.readAll();
00440 s = data.data();
00441 eof = s + data.size();
00442 }
00443
00444 bool fileOptionImmutable = false;
00445 bool groupOptionImmutable = false;
00446 bool groupSkip = false;
00447
00448 int line = 0;
00449 for(; s < eof; s++)
00450 {
00451 line++;
00452
00453 while((s < eof) && isspace(*s) && (*s != '\n'))
00454 s++;
00455
00456
00457 if ((s < eof) && ((*s == '\n') || (*s == '#')))
00458 {
00459 sktoeol:
00460 while ((s < eof) && (*s != '\n'))
00461 s++;
00462 continue;
00463 }
00464 const char *startLine = s;
00465
00466 if (*s == '[')
00467 {
00468
00469 while ((s < eof) && (*s != '\n'))
00470 {
00471 if (*s == ']')
00472 {
00473 if ((s+1 < eof) && (*(s+1) == ']'))
00474 s++;
00475 else
00476 break;
00477 }
00478
00479 s++;
00480 }
00481 const char *e = s;
00482 while ((s < eof) && (*s != '\n')) s++;
00483 if ((e >= eof) || (*e != ']'))
00484 {
00485 fprintf(stderr, "Invalid group header at %s:%d\n", rFile.name().latin1(), line);
00486 continue;
00487 }
00488
00489
00490 if ((e-startLine == 3) &&
00491 (startLine[1] == '$') &&
00492 (startLine[2] == 'i'))
00493 {
00494 fileOptionImmutable = true;
00495 continue;
00496 }
00497
00498 aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
00499
00500
00501
00502 if (aCurrentGroup == "KDE Desktop Entry")
00503 aCurrentGroup = "Desktop Entry";
00504
00505 groupOptionImmutable = fileOptionImmutable;
00506
00507 e++;
00508 if ((e+2 < eof) && (*e++ == '[') && (*e++ == '$'))
00509 {
00510 if (*e == 'i')
00511 {
00512 groupOptionImmutable = true;
00513 }
00514 }
00515
00516 KEntryKey groupKey(aCurrentGroup, 0);
00517 KEntry entry = pConfig->lookupData(groupKey);
00518 groupSkip = entry.bImmutable;
00519
00520 if (groupSkip)
00521 continue;
00522
00523 entry.bImmutable = groupOptionImmutable;
00524 pConfig->putData(groupKey, entry, false);
00525
00526 if (pWriteBackMap)
00527 {
00528
00529 (*pWriteBackMap)[groupKey] = entry;
00530 }
00531
00532 continue;
00533 }
00534 if (groupSkip)
00535 goto sktoeol;
00536
00537 bool optionImmutable = groupOptionImmutable;
00538 bool optionDeleted = false;
00539 bool optionExpand = false;
00540 const char *endOfKey = 0, *locale = 0, *elocale = 0;
00541 for (; (s < eof) && (*s != '\n'); s++)
00542 {
00543 if (*s == '=')
00544 {
00545 if (!endOfKey)
00546 endOfKey = s;
00547 goto haveeq;
00548 }
00549 if (*s == '[')
00550 {
00551 const char *option;
00552 const char *eoption;
00553 endOfKey = s;
00554 option = ++s;
00555 for (;; s++)
00556 {
00557 if ((s >= eof) || (*s == '\n') || (*s == '=')) {
00558 fprintf(stderr, "Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
00559 goto sktoeol;
00560 }
00561 if (*s == ']')
00562 break;
00563 }
00564 eoption = s;
00565 if (*option != '$')
00566 {
00567
00568 if (locale) {
00569 fprintf(stderr, "Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
00570 goto sktoeol;
00571 }
00572 locale = option;
00573 elocale = eoption;
00574 }
00575 else
00576 {
00577
00578 while (option < eoption)
00579 {
00580 option++;
00581 if (*option == 'i')
00582 optionImmutable = true;
00583 else if (*option == 'e')
00584 optionExpand = true;
00585 else if (*option == 'd')
00586 {
00587 optionDeleted = true;
00588 goto haveeq;
00589 }
00590 else if (*option == ']')
00591 break;
00592 }
00593 }
00594 }
00595 }
00596 fprintf(stderr, "Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
00597 continue;
00598
00599 haveeq:
00600 for (endOfKey--; ; endOfKey--)
00601 {
00602 if (endOfKey < startLine)
00603 {
00604 fprintf(stderr, "Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
00605 goto sktoeol;
00606 }
00607 if (!isspace(*endOfKey))
00608 break;
00609 }
00610
00611 const char *st = ++s;
00612 while ((s < eof) && (*s != '\n')) s++;
00613
00614 if (locale) {
00615 unsigned int cl = static_cast<unsigned int>(elocale - locale);
00616 if ((ll != cl) || memcmp(locale, localeString.data(), ll))
00617 {
00618
00619 if ( cl != 1 || ll != 5 || *locale != 'C' || memcmp(localeString.data(), "en_US", 5)) {
00620
00621
00622 if (!pWriteBackMap)
00623 continue;
00624
00625 endOfKey = elocale;
00626 locale = 0;
00627 }
00628 }
00629 }
00630
00631
00632 QCString key(startLine, endOfKey - startLine + 2);
00633 QCString val = printableToString(st, s - st);
00634
00635
00636 KEntryKey aEntryKey(aCurrentGroup, key);
00637 aEntryKey.bLocal = (locale != 0);
00638 aEntryKey.bDefault = bDefault;
00639
00640 KEntry aEntry;
00641 aEntry.mValue = val;
00642 aEntry.bGlobal = bGlobal;
00643 aEntry.bImmutable = optionImmutable;
00644 aEntry.bDeleted = optionDeleted;
00645 aEntry.bExpand = optionExpand;
00646 aEntry.bNLS = (locale != 0);
00647
00648 if (pWriteBackMap) {
00649
00650
00651 pWriteBackMap->insert(aEntryKey, aEntry);
00652 } else {
00653
00654
00655
00656 pConfig->putData(aEntryKey, aEntry, false);
00657 }
00658 }
00659 if (fileOptionImmutable)
00660 bFileImmutable = true;
00661
00662 #ifdef HAVE_MMAP
00663 if (map)
00664 {
00665 munmap(( char* )map, rFile.size());
00666 #ifdef SIGBUS
00667 sigaction (SIGBUS, &mmap_old_sigact, 0);
00668 #endif
00669 }
00670 #endif
00671 }
00672
00673
00674 void KConfigINIBackEnd::sync(bool bMerge)
00675 {
00676
00677 if (!pConfig->isDirty())
00678 return;
00679
00680 bool bEntriesLeft = true;
00681
00682
00683
00684
00685 if (!mfileName.isEmpty()) {
00686
00687 if ((resType!="config") && mLocalFileName[0]=='/')
00688 {
00689 KURL path;
00690 path.setPath(mLocalFileName);
00691 QString dir=path.directory();
00692 KStandardDirs::makeDir(dir);
00693 }
00694
00695
00696
00697
00698
00699 if (checkAccess(mLocalFileName, W_OK)) {
00700
00701
00702 bool mergeLocalFile = bMerge;
00703
00704 if (mergeLocalFile)
00705 {
00706 QFileInfo info(mLocalFileName);
00707 if ((d->localLastSize == info.size()) &&
00708 (d->localLastModified == info.lastModified()))
00709 {
00710
00711 mergeLocalFile = false;
00712 }
00713 else
00714 {
00715
00716 d->localLastModified = QDateTime();
00717 d->localLastSize = 0;
00718 }
00719 }
00720
00721 bEntriesLeft = writeConfigFile( mLocalFileName, false, mergeLocalFile );
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731 if (!mergeLocalFile)
00732 {
00733 QFileInfo info(mLocalFileName);
00734 d->localLastModified = info.lastModified();
00735 d->localLastSize = info.size();
00736 }
00737 }
00738 }
00739
00740
00741
00742
00743 if (bEntriesLeft && useKDEGlobals) {
00744
00745
00746 if (checkAccess ( mGlobalFileName, W_OK )) {
00747 writeConfigFile( mGlobalFileName, true, bMerge );
00748 }
00749 }
00750
00751 }
00752
00753 static void writeEntries(FILE *pStream, const KEntryMap& entryMap, bool defaultGroup, bool &firstEntry, const QCString &localeString)
00754 {
00755
00756 QCString currentGroup;
00757 for (KEntryMapConstIterator aIt = entryMap.begin();
00758 aIt != entryMap.end(); ++aIt)
00759 {
00760 const KEntryKey &key = aIt.key();
00761
00762
00763 if ((key.mGroup != "<default>") == defaultGroup)
00764 continue;
00765
00766
00767 if ((key.bDefault) || key.mKey.isEmpty())
00768 continue;
00769
00770 const KEntry ¤tEntry = *aIt;
00771
00772 KEntryMapConstIterator aTestIt = aIt;
00773 ++aTestIt;
00774 bool hasDefault = (aTestIt != entryMap.end());
00775 if (hasDefault)
00776 {
00777 const KEntryKey &defaultKey = aTestIt.key();
00778 if ((!defaultKey.bDefault) ||
00779 (defaultKey.mKey != key.mKey) ||
00780 (defaultKey.mGroup != key.mGroup) ||
00781 (defaultKey.bLocal != key.bLocal))
00782 hasDefault = false;
00783 }
00784
00785
00786 if (hasDefault)
00787 {
00788
00789 if ((currentEntry.mValue == (*aTestIt).mValue) &&
00790 (currentEntry.bDeleted == (*aTestIt).bDeleted))
00791 continue;
00792 }
00793 else
00794 {
00795
00796 if (currentEntry.bDeleted)
00797 continue;
00798 }
00799
00800 if (!defaultGroup && (currentGroup != key.mGroup)) {
00801 if (!firstEntry)
00802 fprintf(pStream, "\n");
00803 currentGroup = key.mGroup;
00804 fprintf(pStream, "[%s]\n", encodeGroup(currentGroup).data());
00805 }
00806
00807 firstEntry = false;
00808
00809 fputs(key.mKey.data(), pStream);
00810
00811 if ( currentEntry.bNLS )
00812 {
00813 fputc('[', pStream);
00814 fputs(localeString.data(), pStream);
00815 fputc(']', pStream);
00816 }
00817
00818 if (currentEntry.bDeleted)
00819 {
00820 fputs("[$d]\n", pStream);
00821 }
00822 else
00823 {
00824 if (currentEntry.bImmutable || currentEntry.bExpand)
00825 {
00826 fputc('[', pStream);
00827 fputc('$', pStream);
00828 if (currentEntry.bImmutable)
00829 fputc('i', pStream);
00830 if (currentEntry.bExpand)
00831 fputc('e', pStream);
00832
00833 fputc(']', pStream);
00834 }
00835 fputc('=', pStream);
00836 fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
00837 fputc('\n', pStream);
00838 }
00839 }
00840 }
00841
00842 bool KConfigINIBackEnd::getEntryMap(KEntryMap &aTempMap, bool bGlobal,
00843 QFile *mergeFile)
00844 {
00845 bool bEntriesLeft = false;
00846 bFileImmutable = false;
00847
00848
00849 if (mergeFile && mergeFile->open(IO_ReadOnly))
00850 {
00851
00852 parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal, false );
00853
00854 if (bFileImmutable)
00855 return bEntriesLeft;
00856 }
00857
00858 KEntryMap aMap = pConfig->internalEntryMap();
00859
00860
00861 for (KEntryMapIterator aIt = aMap.begin();
00862 aIt != aMap.end(); ++aIt)
00863 {
00864 const KEntry ¤tEntry = *aIt;
00865 if(aIt.key().bDefault)
00866 {
00867 aTempMap.replace(aIt.key(), currentEntry);
00868 continue;
00869 }
00870
00871 if (mergeFile && !currentEntry.bDirty)
00872 continue;
00873
00874
00875
00876 if (currentEntry.bGlobal != bGlobal)
00877 {
00878
00879 bEntriesLeft = true;
00880 continue;
00881 }
00882
00883
00884
00885 KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
00886 if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
00887 continue;
00888
00889 aTempMap.insert(aIt.key(), currentEntry, true);
00890 }
00891
00892 return bEntriesLeft;
00893 }
00894
00895
00896 bool KConfigINIBackEnd::writeConfigFile(QString filename, bool bGlobal,
00897 bool bMerge)
00898 {
00899
00900 if (pConfig->isReadOnly())
00901 return true;
00902
00903 KEntryMap aTempMap;
00904 QFile *mergeFile = (bMerge ? new QFile(filename) : 0);
00905 bool bEntriesLeft = getEntryMap(aTempMap, bGlobal, mergeFile);
00906 delete mergeFile;
00907 if (bFileImmutable) return true;
00908
00909
00910
00911
00912
00913 int fileMode = -1;
00914 bool createNew = true;
00915
00916 struct stat buf;
00917 if (lstat(QFile::encodeName(filename), &buf) == 0)
00918 {
00919 if (S_ISLNK(buf.st_mode))
00920 {
00921
00922 if (stat(QFile::encodeName(filename), &buf) == 0)
00923 {
00924
00925 createNew = false;
00926 }
00927 }
00928 else if (buf.st_uid == getuid())
00929 {
00930
00931 fileMode = buf.st_mode & 0777;
00932 }
00933 else
00934 {
00935
00936
00937 createNew = false;
00938 }
00939 }
00940
00941 KSaveFile *pConfigFile = 0;
00942 FILE *pStream = 0;
00943
00944 if (createNew)
00945 {
00946 pConfigFile = new KSaveFile( filename, 0600 );
00947
00948 if (pConfigFile->status() != 0)
00949 {
00950 delete pConfigFile;
00951 return bEntriesLeft;
00952 }
00953
00954 if (!bGlobal && (fileMode == -1))
00955 fileMode = mFileMode;
00956
00957 if (fileMode != -1)
00958 {
00959 fchmod(pConfigFile->handle(), fileMode);
00960 }
00961
00962 pStream = pConfigFile->fstream();
00963 }
00964 else
00965 {
00966
00967
00968 int fd = open( QFile::encodeName(filename), O_WRONLY | O_TRUNC);
00969 if (fd < 0)
00970 return bEntriesLeft;
00971 pStream = fdopen( fd, "w");
00972 if (!pStream)
00973 {
00974 close(fd);
00975 return bEntriesLeft;
00976 }
00977 }
00978
00979 writeEntries(pStream, aTempMap);
00980
00981 if (pConfigFile)
00982 {
00983 bool bEmptyFile = (ftell(pStream) == 0);
00984 if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
00985 {
00986
00987 ::unlink(QFile::encodeName(filename));
00988 pConfigFile->abort();
00989 }
00990 else
00991 {
00992
00993 pConfigFile->close();
00994 }
00995 delete pConfigFile;
00996 }
00997 else
00998 {
00999 fclose(pStream);
01000 }
01001
01002 return bEntriesLeft;
01003 }
01004
01005 void KConfigINIBackEnd::writeEntries(FILE *pStream, const KEntryMap &aTempMap)
01006 {
01007 bool firstEntry = true;
01008
01009
01010 ::writeEntries(pStream, aTempMap, true, firstEntry, localeString);
01011
01012
01013 ::writeEntries(pStream, aTempMap, false, firstEntry, localeString);
01014 }
01015
01016 void KConfigBackEnd::virtual_hook( int, void* )
01017 { }
01018
01019 void KConfigINIBackEnd::virtual_hook( int id, void* data )
01020 { KConfigBackEnd::virtual_hook( id, data ); }
01021
01022 bool KConfigBackEnd::checkConfigFilesWritable(bool warnUser)
01023 {
01024
01025 bool allWritable = true;
01026 QString errorMsg( i18n("Will not save configuration.\n") );
01027 if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
01028 {
01029 allWritable = false;
01030 errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
01031 }
01032
01033
01034 if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
01035 {
01036 errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
01037 allWritable = false;
01038 }
01039
01040 if (warnUser && !allWritable)
01041 {
01042
01043 errorMsg += i18n("Please contact your system administrator.");
01044 QString cmdToExec = KStandardDirs::findExe(QString("kdialog"));
01045 KApplication *app = kapp;
01046 if (!cmdToExec.isEmpty() && app)
01047 {
01048 KProcess lprocess;
01049 lprocess << cmdToExec << "--title" << app->instanceName() << "--msgbox" << errorMsg.local8Bit();
01050 lprocess.start( KProcess::Block );
01051 }
01052 }
01053 return allWritable;
01054 }