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 }