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 (lstat(QFile::encodeName(filename), &buf) == 0)
00976 {
00977
if (S_ISLNK(buf.st_mode))
00978 {
00979
00980
if (stat(QFile::encodeName(filename), &buf) == 0)
00981 {
00982
00983 createNew =
false;
00984 }
00985 }
00986
else if (buf.st_uid == getuid())
00987 {
00988
00989 fileMode = buf.st_mode & 0777;
00990 }
00991
else
00992 {
00993
00994
00995 createNew =
false;
00996 }
00997 }
00998
00999
KSaveFile *pConfigFile = 0;
01000 FILE *pStream = 0;
01001
01002
if (createNew)
01003 {
01004 pConfigFile =
new KSaveFile( filename, 0600 );
01005
01006
if (pConfigFile->
status() != 0)
01007 {
01008
delete pConfigFile;
01009
return bEntriesLeft;
01010 }
01011
01012
if (!bGlobal && (fileMode == -1))
01013 fileMode = mFileMode;
01014
01015
if (fileMode != -1)
01016 {
01017 fchmod(pConfigFile->
handle(), fileMode);
01018 }
01019
01020 pStream = pConfigFile->
fstream();
01021 }
01022
else
01023 {
01024
01025
01026
int fd = open( QFile::encodeName(filename), O_WRONLY | O_TRUNC);
01027
if (fd < 0)
01028 {
01029
return bEntriesLeft;
01030 }
01031 pStream = fdopen( fd,
"w");
01032
if (!pStream)
01033 {
01034 close(fd);
01035
return bEntriesLeft;
01036 }
01037 }
01038
01039
writeEntries(pStream, aTempMap);
01040
01041
if (pConfigFile)
01042 {
01043
bool bEmptyFile = (ftell(pStream) == 0);
01044
if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
01045 {
01046
01047 ::unlink(QFile::encodeName(filename));
01048 pConfigFile->
abort();
01049 }
01050
else
01051 {
01052
01053 pConfigFile->
close();
01054 }
01055
delete pConfigFile;
01056 }
01057
else
01058 {
01059 fclose(pStream);
01060 }
01061
01062
return bEntriesLeft;
01063 }
01064
01065 void KConfigINIBackEnd::writeEntries(FILE *pStream,
const KEntryMap &aTempMap)
01066 {
01067
bool firstEntry =
true;
01068
01069
01070 ::writeEntries(pStream, aTempMap,
true, firstEntry, localeString);
01071
01072
01073 ::writeEntries(pStream, aTempMap,
false, firstEntry, localeString);
01074 }
01075
01076
void KConfigBackEnd::virtual_hook(
int,
void* )
01077 { }
01078
01079
void KConfigINIBackEnd::virtual_hook(
int id,
void* data )
01080 { KConfigBackEnd::virtual_hook(
id, data ); }
01081
01082 bool KConfigBackEnd::checkConfigFilesWritable(
bool warnUser)
01083 {
01084
01085
bool allWritable =
true;
01086
QString errorMsg( i18n(
"Will not save configuration.\n") );
01087
if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
01088 {
01089 allWritable =
false;
01090 errorMsg += i18n(
"Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
01091 }
01092
01093
01094
if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
01095 {
01096 errorMsg += i18n(
"Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
01097 allWritable =
false;
01098 }
01099
01100
if (warnUser && !allWritable)
01101 {
01102
01103 errorMsg += i18n(
"Please contact your system administrator.");
01104
QString cmdToExec =
KStandardDirs::findExe(
QString(
"kdialog"));
01105
KApplication *app = kapp;
01106
if (!cmdToExec.isEmpty() && app)
01107 {
01108
KProcess lprocess;
01109 lprocess << cmdToExec <<
"--title" << app->
instanceName() <<
"--msgbox" << errorMsg.local8Bit();
01110 lprocess.
start( KProcess::Block );
01111 }
01112 }
01113
return allWritable;
01114 }