1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include "system.hxx"
21 #include "readwrite_helper.hxx"
22 #include "file_url.hxx"
23 #include "unixerrnostring.hxx"
24
25 #include <osl/diagnose.h>
26 #include <osl/profile.h>
27 #include <osl/process.h>
28 #include <osl/thread.h>
29 #include <rtl/alloc.h>
30 #include <sal/log.hxx>
31
32 #define LINES_INI 32
33 #define LINES_ADD 10
34 #define SECTIONS_INI 5
35 #define SECTIONS_ADD 3
36 #define ENTRIES_INI 5
37 #define ENTRIES_ADD 3
38
39 #define STR_INI_BOOLYES "yes"
40 #define STR_INI_BOOLON "on"
41 #define STR_INI_BOOLONE "1"
42 #define STR_INI_BOOLNO "no"
43 #define STR_INI_BOOLOFF "off"
44 #define STR_INI_BOOLZERO "0"
45
46 #define FLG_USER 0x00FF
47 #define FLG_AUTOOPEN 0x0100
48 #define FLG_MODIFIED 0x0200
49
50 #define DEFAULT_PMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
51
52 typedef time_t osl_TStamp;
53
54 enum osl_TLockMode
55 {
56 un_lock, read_lock, write_lock
57 };
58
59 struct osl_TFile
60 {
61 int m_Handle;
62 sal_Char* m_pReadPtr;
63 sal_Char m_ReadBuf[512];
64 sal_Char* m_pWriteBuf;
65 sal_uInt32 m_nWriteBufLen;
66 sal_uInt32 m_nWriteBufFree;
67 };
68
69 struct osl_TProfileEntry
70 {
71 sal_uInt32 m_Line;
72 sal_uInt32 m_Offset;
73 sal_uInt32 m_Len;
74 };
75
76 struct osl_TProfileSection
77 {
78 sal_uInt32 m_Line;
79 sal_uInt32 m_Offset;
80 sal_uInt32 m_Len;
81 sal_uInt32 m_NoEntries;
82 sal_uInt32 m_MaxEntries;
83 osl_TProfileEntry* m_Entries;
84 };
85
86 /* Profile-data structure hidden behind oslProfile: */
87 struct osl_TProfileImpl
88 {
89 sal_uInt32 m_Flags;
90 osl_TFile* m_pFile;
91 osl_TStamp m_Stamp;
92 sal_Char m_FileName[PATH_MAX + 1];
93 sal_uInt32 m_NoLines;
94 sal_uInt32 m_MaxLines;
95 sal_uInt32 m_NoSections;
96 sal_uInt32 m_MaxSections;
97 sal_Char** m_Lines;
98 osl_TProfileSection* m_Sections;
99 pthread_mutex_t m_AccessLock;
100 bool m_bIsValid;
101 };
102
103 static osl_TFile* openFileImpl(const sal_Char* pszFilename, oslProfileOption ProfileFlags);
104 static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags);
105 static bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode);
106 static bool OslProfile_rewindFile(osl_TFile* pFile, bool bTruncate);
107 static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile);
108
109 static sal_Char* OslProfile_getLine(osl_TFile* pFile);
110 static bool OslProfile_putLine(osl_TFile* pFile, const sal_Char *pszLine);
111 static sal_Char* stripBlanks(sal_Char* String, sal_uInt32* pLen);
112 static sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line);
113 static sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo);
114 static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo);
115 static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection,
116 sal_uInt32 NoEntry, sal_uInt32 Line,
117 sal_Char* Entry, sal_uInt32 Len);
118 static bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection,
119 int Line, sal_Char* Entry, sal_uInt32 Len);
120 static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry);
121 static bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len);
122 static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection);
123 static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section,
124 const sal_Char* Entry, sal_uInt32 *pNoEntry);
125 static bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile);
126 static bool storeProfile(osl_TProfileImpl* pProfile, bool bCleanup);
127 static osl_TProfileImpl* acquireProfile(oslProfile Profile, bool bWriteable);
128 static bool releaseProfile(osl_TProfileImpl* pProfile);
129
130 static bool writeProfileImpl (osl_TFile* pFile);
131 static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl*);
132 static bool osl_ProfileSwapProfileNames(osl_TProfileImpl*);
133 static void osl_ProfileGenerateExtension(const sal_Char* pszFileName, const sal_Char* pszExtension, sal_Char* pszTmpName, int BufferMaxLen);
134 static oslProfile osl_psz_openProfile(const sal_Char *pszProfileName, oslProfileOption Flags);
135
osl_openProfile(rtl_uString * ustrProfileName,oslProfileOption Options)136 oslProfile SAL_CALL osl_openProfile(rtl_uString *ustrProfileName, oslProfileOption Options)
137 {
138 char profilePath[PATH_MAX] = "";
139 return
140 (ustrProfileName == nullptr
141 || ustrProfileName->buffer[0] == 0
142 || (FileURLToPath(profilePath, PATH_MAX, ustrProfileName)
143 == osl_File_E_None))
144 ? osl_psz_openProfile(profilePath, Options)
145 : nullptr;
146 }
147
osl_psz_openProfile(const sal_Char * pszProfileName,oslProfileOption Flags)148 static oslProfile osl_psz_openProfile(const sal_Char *pszProfileName, oslProfileOption Flags)
149 {
150 osl_TFile* pFile;
151 osl_TProfileImpl* pProfile;
152 bool bRet = false;
153
154 if ( ( pFile = openFileImpl(pszProfileName, Flags ) ) == nullptr )
155 {
156 return nullptr;
157 }
158
159 pProfile = static_cast<osl_TProfileImpl*>(calloc(1, sizeof(osl_TProfileImpl)));
160
161 if ( pProfile == nullptr )
162 {
163 closeFileImpl(pFile, Flags);
164 return nullptr;
165 }
166
167 pProfile->m_Flags = Flags & FLG_USER;
168
169 if ( Flags & ( osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) )
170 {
171 pProfile->m_pFile = pFile;
172 }
173
174 pthread_mutex_init(&(pProfile->m_AccessLock),PTHREAD_MUTEXATTR_DEFAULT);
175 pProfile->m_bIsValid = true;
176
177 pProfile->m_Stamp = OslProfile_getFileStamp(pFile);
178 bRet=loadProfile(pFile, pProfile);
179 bRet &= realpath(pszProfileName, pProfile->m_FileName) != nullptr;
180 SAL_WARN_IF(!bRet, "sal.osl", "realpath(pszProfileName, pProfile->m_FileName) != NULL ==> false");
181
182 if (pProfile->m_pFile == nullptr)
183 closeFileImpl(pFile,pProfile->m_Flags);
184
185 // coverity[leaked_storage] - pFile is not leaked
186 return pProfile;
187 }
188
osl_closeProfile(oslProfile Profile)189 sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile)
190 {
191 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
192 osl_TProfileImpl* pTmpProfile;
193
194 if ( Profile == nullptr )
195 {
196 return false;
197 }
198
199 pthread_mutex_lock(&(pProfile->m_AccessLock));
200
201 if ( !pProfile->m_bIsValid )
202 {
203 SAL_WARN("sal.osl", "!pProfile->m_bIsValid");
204 pthread_mutex_unlock(&(pProfile->m_AccessLock));
205
206 return false;
207 }
208
209 pProfile->m_bIsValid = false;
210
211 if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) && ( pProfile->m_Flags & FLG_MODIFIED ) )
212 {
213 pTmpProfile = acquireProfile(Profile, true);
214
215 if ( pTmpProfile != nullptr )
216 {
217 bool bRet = storeProfile(pTmpProfile, true);
218 SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pTmpProfile, true) ==> false");
219 }
220 }
221 else
222 {
223 pTmpProfile = acquireProfile(Profile, false);
224 }
225
226 if ( pTmpProfile == nullptr )
227 {
228 pthread_mutex_unlock(&(pProfile->m_AccessLock));
229
230 SAL_INFO("sal.osl", "Out osl_closeProfile [pProfile==0]");
231 return false;
232 }
233
234 pProfile = pTmpProfile;
235
236 if (pProfile->m_pFile != nullptr)
237 closeFileImpl(pProfile->m_pFile,pProfile->m_Flags);
238
239 pProfile->m_pFile = nullptr;
240 pProfile->m_FileName[0] = '\0';
241
242 /* release whole profile data types memory */
243 if ( pProfile->m_NoLines > 0)
244 {
245 unsigned int idx=0;
246 if ( pProfile->m_Lines != nullptr )
247 {
248 for ( idx = 0 ; idx < pProfile->m_NoLines ; ++idx)
249 {
250 if ( pProfile->m_Lines[idx] != nullptr )
251 {
252 free(pProfile->m_Lines[idx]);
253 pProfile->m_Lines[idx]=nullptr;
254 }
255 }
256 free(pProfile->m_Lines);
257 pProfile->m_Lines=nullptr;
258 }
259 if ( pProfile->m_Sections != nullptr )
260 {
261 /*osl_TProfileSection* pSections=pProfile->m_Sections;*/
262 for ( idx = 0 ; idx < pProfile->m_NoSections ; ++idx )
263 {
264 if ( pProfile->m_Sections[idx].m_Entries != nullptr )
265 {
266 free(pProfile->m_Sections[idx].m_Entries);
267 pProfile->m_Sections[idx].m_Entries=nullptr;
268 }
269 }
270 free(pProfile->m_Sections);
271 pProfile->m_Sections=nullptr;
272 }
273 }
274
275 pthread_mutex_unlock(&(pProfile->m_AccessLock));
276
277 pthread_mutex_destroy(&(pProfile->m_AccessLock));
278
279 free(pProfile);
280
281 return true;
282 }
283
osl_flushProfile(oslProfile Profile)284 sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile)
285 {
286 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
287 osl_TFile* pFile;
288 bool bRet = false;
289
290 if ( pProfile == nullptr )
291 {
292 return false;
293 }
294
295 pthread_mutex_lock(&(pProfile->m_AccessLock));
296
297 if ( !pProfile->m_bIsValid )
298 {
299 SAL_WARN_IF(!pProfile->m_bIsValid, "sal.osl", "!pProfile->m_bIsValid");
300 pthread_mutex_unlock(&(pProfile->m_AccessLock));
301 return false;
302 }
303
304 pFile = pProfile->m_pFile;
305 if ( !( pFile != nullptr && pFile->m_Handle >= 0 ) )
306 {
307 pthread_mutex_unlock(&(pProfile->m_AccessLock));
308
309 return false;
310 }
311
312 if ( pProfile->m_Flags & FLG_MODIFIED )
313 {
314 bRet = storeProfile(pProfile, false);
315 SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pProfile, false) ==> false");
316 }
317
318 pthread_mutex_unlock(&(pProfile->m_AccessLock));
319 return bRet;
320 }
321
writeProfileImpl(osl_TFile * pFile)322 static bool writeProfileImpl(osl_TFile* pFile)
323 {
324 if ( !( pFile != nullptr && pFile->m_Handle >= 0 ) || ( pFile->m_pWriteBuf == nullptr ) )
325 {
326 return false;
327 }
328
329 SAL_WARN_IF(
330 (strlen(pFile->m_pWriteBuf)
331 != pFile->m_nWriteBufLen - pFile->m_nWriteBufFree),
332 "sal.osl",
333 strlen(pFile->m_pWriteBuf) << " != "
334 << (pFile->m_nWriteBufLen - pFile->m_nWriteBufFree));
335
336 if ( !safeWrite(pFile->m_Handle, pFile->m_pWriteBuf, pFile->m_nWriteBufLen - pFile->m_nWriteBufFree) )
337 {
338 SAL_INFO("sal.osl", "write failed: " << UnixErrnoString(errno));
339 return false;
340 }
341
342 free(pFile->m_pWriteBuf);
343 pFile->m_pWriteBuf=nullptr;
344 pFile->m_nWriteBufLen=0;
345 pFile->m_nWriteBufFree=0;
346
347 return true;
348 }
349
osl_readProfileString(oslProfile Profile,const sal_Char * pszSection,const sal_Char * pszEntry,sal_Char * pszString,sal_uInt32 MaxLen,const sal_Char * pszDefault)350 sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile,
351 const sal_Char* pszSection,
352 const sal_Char* pszEntry,
353 sal_Char* pszString,
354 sal_uInt32 MaxLen,
355 const sal_Char* pszDefault)
356 {
357 sal_uInt32 NoEntry;
358 sal_Char* pStr=nullptr;
359 osl_TProfileImpl* pProfile=nullptr;
360 osl_TProfileImpl* pTmpProfile=nullptr;
361 bool bRet = false;
362
363 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
364
365 if ( pTmpProfile == nullptr )
366 {
367 return false;
368 }
369
370 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
371
372 if ( !pTmpProfile->m_bIsValid )
373 {
374 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
375
376 return false;
377 }
378
379 pProfile = acquireProfile(Profile, false);
380
381 if ( pProfile == nullptr )
382 {
383 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
384
385 return false;
386 }
387
388 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
389 {
390 osl_TProfileSection* pSec;
391 if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != nullptr) &&
392 (NoEntry < pSec->m_NoEntries) &&
393 ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line],
394 '=')) != nullptr))
395 {
396 pStr++;
397 }
398 else
399 {
400 pStr=const_cast<sal_Char*>(pszDefault);
401 }
402
403 if ( pStr != nullptr )
404 {
405 pStr = stripBlanks(pStr, nullptr);
406 MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr);
407 pStr = stripBlanks(pStr, &MaxLen);
408 strncpy(pszString, pStr, MaxLen);
409 pszString[MaxLen] = '\0';
410 }
411 }
412 else
413 { /* not implemented */ }
414
415 bRet=releaseProfile(pProfile);
416 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
417
418 if ( pStr == nullptr )
419 {
420 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
421
422 return false;
423 }
424
425 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
426
427 return true;
428 }
429
osl_readProfileBool(oslProfile Profile,const sal_Char * pszSection,const sal_Char * pszEntry,sal_Bool Default)430 sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile,
431 const sal_Char* pszSection,
432 const sal_Char* pszEntry,
433 sal_Bool Default)
434 {
435 sal_Char Line[32];
436 Line[0] = '\0';
437
438 if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), ""))
439 {
440 if ((strcasecmp(Line, STR_INI_BOOLYES) == 0) ||
441 (strcasecmp(Line, STR_INI_BOOLON) == 0) ||
442 (strcasecmp(Line, STR_INI_BOOLONE) == 0))
443 Default = true;
444 else
445 if ((strcasecmp(Line, STR_INI_BOOLNO) == 0) ||
446 (strcasecmp(Line, STR_INI_BOOLOFF) == 0) ||
447 (strcasecmp(Line, STR_INI_BOOLZERO) == 0))
448 Default = false;
449 }
450
451 return Default;
452 }
453
osl_readProfileIdent(oslProfile Profile,const sal_Char * pszSection,const sal_Char * pszEntry,sal_uInt32 FirstId,const sal_Char * Strings[],sal_uInt32 Default)454 sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile,
455 const sal_Char* pszSection,
456 const sal_Char* pszEntry,
457 sal_uInt32 FirstId,
458 const sal_Char* Strings[],
459 sal_uInt32 Default)
460 {
461 sal_uInt32 i;
462 sal_Char Line[256];
463 Line[0] = '\0';
464
465 if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), ""))
466 {
467 i = 0;
468 while (Strings[i] != nullptr)
469 {
470 if (strcasecmp(Line, Strings[i]) == 0)
471 {
472 Default = i + FirstId;
473 break;
474 }
475 i++;
476 }
477 }
478
479 return Default;
480 }
481
osl_writeProfileString(oslProfile Profile,const sal_Char * pszSection,const sal_Char * pszEntry,const sal_Char * pszString)482 sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile,
483 const sal_Char* pszSection,
484 const sal_Char* pszEntry,
485 const sal_Char* pszString)
486 {
487 sal_uInt32 i;
488 bool bRet = false;
489 sal_uInt32 NoEntry;
490 sal_Char* pStr;
491 sal_Char* Line = nullptr;
492 osl_TProfileSection* pSec;
493 osl_TProfileImpl* pProfile = nullptr;
494 osl_TProfileImpl* pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
495
496 if ( pTmpProfile == nullptr )
497 {
498 return false;
499 }
500
501 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
502
503 if ( !pTmpProfile->m_bIsValid )
504 {
505 SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid");
506 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
507
508 return false;
509 }
510
511 pProfile=acquireProfile(Profile, true);
512
513 if (pProfile == nullptr)
514 {
515 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
516
517 return false;
518 }
519
520 Line = static_cast<sal_Char*>(malloc(strlen(pszEntry)+strlen(pszString)+48));
521
522 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
523 {
524 if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == nullptr)
525 {
526 Line[0] = '\0';
527 addLine(pProfile, Line);
528
529 Line[0] = '[';
530 strcpy(&Line[1], pszSection);
531 Line[1 + strlen(pszSection)] = ']';
532 Line[2 + strlen(pszSection)] = '\0';
533
534 if (((pStr = addLine(pProfile, Line)) == nullptr) ||
535 (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection))))
536 {
537 bRet=releaseProfile(pProfile);
538 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
539
540 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
541
542 free(Line);
543 return false;
544 }
545
546 pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1];
547 NoEntry = pSec->m_NoEntries;
548 }
549
550 Line[0] = '\0';
551 strcpy(&Line[0], pszEntry);
552 Line[0 + strlen(pszEntry)] = '=';
553 strcpy(&Line[1 + strlen(pszEntry)], pszString);
554
555 if (NoEntry >= pSec->m_NoEntries)
556 {
557 if (pSec->m_NoEntries > 0)
558 i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1;
559 else
560 i = pSec->m_Line + 1;
561
562 if (((pStr = insertLine(pProfile, Line, i)) == nullptr) ||
563 (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry))))
564 {
565 bRet=releaseProfile(pProfile);
566 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
567
568 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
569 free(Line);
570
571 return false;
572 }
573
574 pProfile->m_Flags |= FLG_MODIFIED;
575 }
576 else
577 {
578 i = pSec->m_Entries[NoEntry].m_Line;
579 free(pProfile->m_Lines[i]);
580 pProfile->m_Lines[i] = strdup(Line);
581 setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry));
582
583 pProfile->m_Flags |= FLG_MODIFIED;
584 }
585 }
586 else {
587 /* not implemented */
588 }
589
590 bRet = releaseProfile(pProfile);
591 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
592
593 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
594 if ( Line!= nullptr )
595 {
596 free(Line);
597 }
598
599 return bRet;
600 }
601
osl_writeProfileBool(oslProfile Profile,const sal_Char * pszSection,const sal_Char * pszEntry,sal_Bool Value)602 sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile,
603 const sal_Char* pszSection,
604 const sal_Char* pszEntry,
605 sal_Bool Value)
606 {
607 bool bRet = false;
608
609 if (Value)
610 bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE);
611 else
612 bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO);
613
614 return bRet;
615 }
616
osl_writeProfileIdent(oslProfile Profile,const sal_Char * pszSection,const sal_Char * pszEntry,sal_uInt32 FirstId,const sal_Char * Strings[],sal_uInt32 Value)617 sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile,
618 const sal_Char* pszSection,
619 const sal_Char* pszEntry,
620 sal_uInt32 FirstId,
621 const sal_Char* Strings[],
622 sal_uInt32 Value)
623 {
624 int i, n = 0;
625 bool bRet = false;
626
627 while (Strings[n] != nullptr)
628 ++n;
629
630 if ((i = Value - FirstId) >= n)
631 bRet = false;
632 else
633 bRet = osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]);
634
635 return bRet;
636 }
637
osl_removeProfileEntry(oslProfile Profile,const sal_Char * pszSection,const sal_Char * pszEntry)638 sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile,
639 const sal_Char *pszSection,
640 const sal_Char *pszEntry)
641 {
642 sal_uInt32 NoEntry;
643 osl_TProfileImpl* pProfile = nullptr;
644 osl_TProfileImpl* pTmpProfile = nullptr;
645 bool bRet = false;
646
647 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
648
649 if ( pTmpProfile == nullptr )
650 {
651 return false;
652 }
653
654 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
655
656 if ( !pTmpProfile->m_bIsValid )
657 {
658 SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid");
659 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
660 return false;
661 }
662
663 pProfile = acquireProfile(Profile, true);
664
665 if (pProfile == nullptr)
666 {
667 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
668
669 return false;
670 }
671
672 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
673 {
674 osl_TProfileSection* pSec;
675 if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != nullptr) &&
676 (NoEntry < pSec->m_NoEntries))
677 {
678 removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line);
679 removeEntry(pSec, NoEntry);
680 if (pSec->m_NoEntries == 0)
681 {
682 removeLine(pProfile, pSec->m_Line);
683
684 /* remove any empty separation line */
685 if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0'))
686 removeLine(pProfile, pSec->m_Line - 1);
687
688 removeSection(pProfile, pSec);
689 }
690
691 pProfile->m_Flags |= FLG_MODIFIED;
692 }
693 }
694 else
695 { /* not implemented */ }
696
697 bRet = releaseProfile(pProfile);
698 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
699
700 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
701
702 return bRet;
703 }
704
osl_getProfileSectionEntries(oslProfile Profile,const sal_Char * pszSection,sal_Char * pszBuffer,sal_uInt32 MaxLen)705 sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile,
706 const sal_Char *pszSection,
707 sal_Char* pszBuffer,
708 sal_uInt32 MaxLen)
709 {
710 sal_uInt32 i, n = 0;
711 sal_uInt32 NoEntry;
712 osl_TProfileImpl* pProfile = nullptr;
713 osl_TProfileImpl* pTmpProfile = nullptr;
714 bool bRet = false;
715
716 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
717
718 if ( pTmpProfile == nullptr )
719 {
720 return 0;
721
722 }
723
724 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
725
726 if ( !pTmpProfile->m_bIsValid )
727 {
728 SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid");
729
730 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
731
732 return 0;
733 }
734
735 pProfile = acquireProfile(Profile, false);
736
737 if (pProfile == nullptr)
738 {
739 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
740
741 return 0;
742 }
743
744 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
745 {
746 osl_TProfileSection* pSec;
747 if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != nullptr)
748 {
749 if (MaxLen != 0)
750 {
751 for (i = 0; i < pSec->m_NoEntries; i++)
752 {
753 if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen)
754 {
755 strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line]
756 [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len);
757 n += pSec->m_Entries[i].m_Len;
758 pszBuffer[n++] = '\0';
759 }
760 else
761 break;
762
763 }
764
765 pszBuffer[n++] = '\0';
766 }
767 else
768 {
769 for (i = 0; i < pSec->m_NoEntries; i++)
770 n += pSec->m_Entries[i].m_Len + 1;
771
772 n += 1;
773 }
774 }
775 else
776 n = 0;
777 }
778 else {
779 /* not implemented */
780 }
781
782 bRet=releaseProfile(pProfile);
783 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
784
785 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
786
787 return n;
788 }
789
osl_getProfileSections(oslProfile Profile,sal_Char * pszBuffer,sal_uInt32 MaxLen)790 sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile,
791 sal_Char* pszBuffer,
792 sal_uInt32 MaxLen)
793 {
794 sal_uInt32 i, n = 0;
795 osl_TProfileImpl* pProfile = nullptr;
796 osl_TProfileImpl* pTmpProfile = nullptr;
797 bool bRet = false;
798
799 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
800
801 if ( pTmpProfile == nullptr )
802 {
803 return 0;
804 }
805
806 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
807
808 if ( !pTmpProfile->m_bIsValid )
809 {
810 SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid");
811 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
812
813 return 0;
814 }
815
816 pProfile = acquireProfile(Profile, false);
817
818 if (pProfile == nullptr)
819 {
820 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
821
822 return 0;
823 }
824
825 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
826 {
827 if (MaxLen != 0)
828 {
829 for (i = 0; i < pProfile->m_NoSections; i++)
830 {
831 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
832
833 if ((n + pSec->m_Len + 1) < MaxLen)
834 {
835 strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset],
836 pSec->m_Len);
837 n += pSec->m_Len;
838 pszBuffer[n++] = '\0';
839 }
840 else
841 break;
842 }
843
844 pszBuffer[n++] = '\0';
845 }
846 else
847 {
848 for (i = 0; i < pProfile->m_NoSections; i++)
849 n += pProfile->m_Sections[i].m_Len + 1;
850
851 n += 1;
852 }
853 }
854 else
855 { /* not implemented */ }
856
857 bRet=releaseProfile(pProfile);
858 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
859
860 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
861
862 return n;
863 }
864
OslProfile_getFileStamp(osl_TFile * pFile)865 static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile)
866 {
867 struct stat status;
868
869 if ( (pFile->m_Handle < 0) || (fstat(pFile->m_Handle, &status) < 0) )
870 {
871 return 0;
872 }
873
874 return status.st_mtime;
875 }
876
OslProfile_lockFile(const osl_TFile * pFile,osl_TLockMode eMode)877 static bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode)
878 {
879 struct flock lock;
880 static bool const bLockingDisabled = getenv( "STAR_PROFILE_LOCKING_DISABLED" ) != nullptr;
881
882 if (pFile->m_Handle < 0)
883 {
884 return false;
885 }
886
887 if ( bLockingDisabled )
888 {
889 return true;
890 }
891
892 lock.l_start = 0;
893 lock.l_whence = SEEK_SET;
894 lock.l_len = 0;
895
896 switch (eMode)
897 {
898 case un_lock:
899 lock.l_type = F_UNLCK;
900 break;
901
902 case read_lock:
903 lock.l_type = F_RDLCK;
904 break;
905
906 case write_lock:
907 lock.l_type = F_WRLCK;
908 break;
909 }
910
911 #ifndef MACOSX
912 if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 )
913 #else
914 /* Mac OSX will return ENOTSUP for webdav drives so we should ignore it */
915 if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 && errno != ENOTSUP )
916 #endif
917 {
918 SAL_INFO("sal.osl", "fcntl failed: " << UnixErrnoString(errno));
919 return false;
920 }
921
922 return true;
923 }
924
openFileImpl(const sal_Char * pszFilename,oslProfileOption ProfileFlags)925 static osl_TFile* openFileImpl(const sal_Char* pszFilename, oslProfileOption ProfileFlags )
926 {
927 int Flags;
928 osl_TFile* pFile = static_cast<osl_TFile*>(calloc(1, sizeof(osl_TFile)));
929 bool bWriteable = false;
930
931 if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) )
932 {
933 bWriteable = true;
934 }
935
936 if (! bWriteable)
937 {
938 pFile->m_Handle = open(pszFilename, O_RDONLY);
939
940 if (pFile->m_Handle == -1)
941 {
942 int e = errno;
943 SAL_INFO("sal.file", "open(" << pszFilename << ",O_RDONLY): " << UnixErrnoString(e));
944 }
945 else
946 SAL_INFO("sal.file", "open(" << pszFilename << ",O_RDONLY) => " << pFile->m_Handle);
947
948 /* mfe: argghh!!! do not check if the file could be opened */
949 /* default mode expects it that way!!! */
950 }
951 else
952 {
953 if (((pFile->m_Handle = open(pszFilename, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PMODE)) < 0) &&
954 ((pFile->m_Handle = open(pszFilename, O_RDWR)) < 0))
955 {
956 int e = errno;
957 SAL_INFO("sal.file", "open(" << pszFilename << ",...): " << UnixErrnoString(e));
958 free(pFile);
959 return nullptr;
960 }
961 else
962 SAL_INFO("sal.file", "open(" << pszFilename << ",...) => " << pFile->m_Handle);
963 }
964
965 /* set close-on-exec flag */
966 if ((Flags = fcntl(pFile->m_Handle, F_GETFD, 0)) != -1)
967 {
968 Flags |= FD_CLOEXEC;
969 int e = fcntl(pFile->m_Handle, F_SETFD, Flags);
970 SAL_INFO_IF(
971 e != 0, "sal.osl",
972 "fcntl to set FD_CLOEXEC failed for " << pszFilename);
973 }
974
975 pFile->m_pWriteBuf=nullptr;
976 pFile->m_nWriteBufFree=0;
977 pFile->m_nWriteBufLen=0;
978
979 if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) )
980 {
981 OslProfile_lockFile(pFile, bWriteable ? write_lock : read_lock);
982 }
983
984 return pFile;
985 }
986
closeFileImpl(osl_TFile * pFile,oslProfileOption Flags)987 static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags)
988 {
989 osl_TStamp stamp = 0;
990
991 if ( pFile == nullptr )
992 {
993 return stamp;
994 }
995
996 if ( pFile->m_Handle >= 0 )
997 {
998 stamp = OslProfile_getFileStamp(pFile);
999
1000 if ( Flags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) )
1001 {
1002 OslProfile_lockFile(pFile, un_lock);
1003 }
1004
1005 close(pFile->m_Handle);
1006 SAL_INFO("sal.file", "close(" << pFile->m_Handle << ")");
1007 pFile->m_Handle = -1;
1008 }
1009
1010 if ( pFile->m_pWriteBuf )
1011 {
1012 free(pFile->m_pWriteBuf);
1013 }
1014
1015 free(pFile);
1016
1017 return stamp;
1018 }
1019
OslProfile_rewindFile(osl_TFile * pFile,bool bTruncate)1020 static bool OslProfile_rewindFile(osl_TFile* pFile, bool bTruncate)
1021 {
1022 bool bRet = true;
1023
1024 if (pFile->m_Handle >= 0)
1025 {
1026 pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);
1027
1028 bRet = (lseek(pFile->m_Handle, SEEK_SET, 0L) == 0);
1029
1030 if (bTruncate)
1031 {
1032 bRet &= (ftruncate(pFile->m_Handle, 0L) == 0);
1033 }
1034
1035 }
1036
1037 return bRet;
1038 }
1039
OslProfile_getLine(osl_TFile * pFile)1040 static sal_Char* OslProfile_getLine(osl_TFile* pFile)
1041 {
1042 int Max, Free, nLineBytes = 0;
1043 sal_Char* pChr;
1044 sal_Char* pLine = nullptr;
1045 sal_Char* pNewLine;
1046
1047 if ( pFile == nullptr )
1048 {
1049 return nullptr;
1050 }
1051
1052 if (pFile->m_Handle < 0)
1053 return nullptr;
1054
1055 do
1056 {
1057 int Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf);
1058
1059 if (Bytes <= 1)
1060 {
1061 /* refill buffer */
1062 memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes);
1063 pFile->m_pReadPtr = pFile->m_ReadBuf;
1064
1065 Free = sizeof(pFile->m_ReadBuf) - Bytes;
1066
1067 if ((Max = read(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free)) < 0)
1068 {
1069 SAL_INFO("sal.osl", "read failed: " << UnixErrnoString(errno));
1070
1071 if( pLine )
1072 free( pLine );
1073 pLine = nullptr;
1074 break;
1075 }
1076
1077 if (Max < Free)
1078 {
1079 if ((Max == 0) && ! pLine)
1080 break;
1081
1082 pFile->m_ReadBuf[Bytes + Max] = '\0';
1083 }
1084 }
1085
1086 for (pChr = pFile->m_pReadPtr;
1087 (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') &&
1088 (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1));
1089 pChr++);
1090
1091 Max = pChr - pFile->m_pReadPtr;
1092 pNewLine = static_cast<sal_Char*>(malloc( nLineBytes + Max + 1 ));
1093 if( pLine )
1094 {
1095 memcpy( pNewLine, pLine, nLineBytes );
1096 free( pLine );
1097 }
1098 memcpy(pNewLine+nLineBytes, pFile->m_pReadPtr, Max);
1099 nLineBytes += Max;
1100 pNewLine[ nLineBytes ] = 0;
1101 pLine = pNewLine;
1102
1103 if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1))
1104 {
1105 if (*pChr != '\0')
1106 {
1107 if ((pChr[0] == '\r') && (pChr[1] == '\n'))
1108 pChr += 2;
1109 else
1110 pChr += 1;
1111 }
1112
1113 if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) &&
1114 (*pChr == '\0'))
1115 pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);
1116
1117 /* setting Max to -1 indicates terminating read loop */
1118 Max = -1;
1119 }
1120
1121 pFile->m_pReadPtr = pChr;
1122 }
1123 while (Max > 0) ;
1124
1125 return pLine;
1126 }
1127
OslProfile_putLine(osl_TFile * pFile,const sal_Char * pszLine)1128 static bool OslProfile_putLine(osl_TFile* pFile, const sal_Char *pszLine)
1129 {
1130 unsigned int Len = strlen(pszLine);
1131
1132 if ( pFile == nullptr || pFile->m_Handle < 0 )
1133 {
1134 return false;
1135 }
1136
1137 if ( pFile->m_pWriteBuf == nullptr )
1138 {
1139 pFile->m_pWriteBuf = static_cast<sal_Char*>(malloc(Len+3));
1140 pFile->m_nWriteBufLen = Len+3;
1141 pFile->m_nWriteBufFree = Len+3;
1142 }
1143 else
1144 {
1145 if ( pFile->m_nWriteBufFree <= Len + 3 )
1146 {
1147 sal_Char* pTmp;
1148
1149 pTmp=static_cast<sal_Char*>(realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) ));
1150 if ( pTmp == nullptr )
1151 {
1152 return false;
1153 }
1154 pFile->m_pWriteBuf = pTmp;
1155 pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len );
1156 pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2;
1157 memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree);
1158 }
1159 }
1160
1161 memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1);
1162 pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\n';
1163 pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\0';
1164
1165 pFile->m_nWriteBufFree-=Len+1;
1166
1167 return true;
1168 }
1169
stripBlanks(sal_Char * String,sal_uInt32 * pLen)1170 static sal_Char* stripBlanks(sal_Char* String, sal_uInt32* pLen)
1171 {
1172 if ( ( pLen != nullptr ) && ( *pLen != 0 ) )
1173 {
1174 while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t'))
1175 (*pLen)--;
1176
1177 while ( (*String == ' ') || (*String == '\t') )
1178 {
1179 String++;
1180 (*pLen)--;
1181 }
1182 }
1183 else
1184 while ( (*String == ' ') || (*String == '\t') )
1185 String++;
1186
1187 return String;
1188 }
1189
addLine(osl_TProfileImpl * pProfile,const sal_Char * Line)1190 static sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line)
1191 {
1192 if (pProfile->m_NoLines >= pProfile->m_MaxLines)
1193 {
1194 if (pProfile->m_Lines == nullptr)
1195 {
1196 pProfile->m_MaxLines = LINES_INI;
1197 pProfile->m_Lines = static_cast<sal_Char **>(calloc(pProfile->m_MaxLines, sizeof(sal_Char *)));
1198 }
1199 else
1200 {
1201 unsigned int idx=0;
1202 unsigned int oldmax=pProfile->m_MaxLines;
1203
1204 pProfile->m_MaxLines += LINES_ADD;
1205 pProfile->m_Lines = static_cast<sal_Char **>(realloc(pProfile->m_Lines,
1206 pProfile->m_MaxLines * sizeof(sal_Char *)));
1207 for ( idx = oldmax ; idx < pProfile->m_MaxLines ; ++idx )
1208 {
1209 pProfile->m_Lines[idx]=nullptr;
1210 }
1211 }
1212 }
1213 if (pProfile->m_Lines == nullptr)
1214 {
1215 pProfile->m_NoLines = 0;
1216 pProfile->m_MaxLines = 0;
1217 return nullptr;
1218 }
1219
1220 if ( pProfile->m_Lines[pProfile->m_NoLines] != nullptr )
1221 {
1222 free(pProfile->m_Lines[pProfile->m_NoLines]);
1223 }
1224 pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line);
1225
1226 return pProfile->m_Lines[pProfile->m_NoLines - 1];
1227 }
1228
insertLine(osl_TProfileImpl * pProfile,const sal_Char * Line,sal_uInt32 LineNo)1229 static sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo)
1230 {
1231 if (pProfile->m_NoLines >= pProfile->m_MaxLines)
1232 {
1233 if (pProfile->m_Lines == nullptr)
1234 {
1235 pProfile->m_MaxLines = LINES_INI;
1236 pProfile->m_Lines = static_cast<sal_Char **>(calloc(pProfile->m_MaxLines, sizeof(sal_Char *)));
1237 }
1238 else
1239 {
1240 pProfile->m_MaxLines += LINES_ADD;
1241 pProfile->m_Lines = static_cast<sal_Char **>(realloc(pProfile->m_Lines,
1242 pProfile->m_MaxLines * sizeof(sal_Char *)));
1243
1244 memset(&pProfile->m_Lines[pProfile->m_NoLines],
1245 0,
1246 (pProfile->m_MaxLines - pProfile->m_NoLines - 1) * sizeof(sal_Char*));
1247 }
1248
1249 if (pProfile->m_Lines == nullptr)
1250 {
1251 pProfile->m_NoLines = 0;
1252 pProfile->m_MaxLines = 0;
1253 return nullptr;
1254 }
1255 }
1256
1257 LineNo = std::min(LineNo, pProfile->m_NoLines);
1258
1259 if (LineNo < pProfile->m_NoLines)
1260 {
1261 sal_uInt32 i, n;
1262
1263 memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo],
1264 (pProfile->m_NoLines - LineNo) * sizeof(sal_Char *));
1265
1266 /* adjust line references */
1267 for (i = 0; i < pProfile->m_NoSections; i++)
1268 {
1269 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
1270
1271 if (pSec->m_Line >= LineNo)
1272 pSec->m_Line++;
1273
1274 for (n = 0; n < pSec->m_NoEntries; n++)
1275 if (pSec->m_Entries[n].m_Line >= LineNo)
1276 pSec->m_Entries[n].m_Line++;
1277 }
1278 }
1279
1280 pProfile->m_NoLines++;
1281
1282 pProfile->m_Lines[LineNo] = strdup(Line);
1283
1284 return pProfile->m_Lines[LineNo];
1285 }
1286
removeLine(osl_TProfileImpl * pProfile,sal_uInt32 LineNo)1287 static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo)
1288 {
1289 if (LineNo < pProfile->m_NoLines)
1290 {
1291 free(pProfile->m_Lines[LineNo]);
1292 pProfile->m_Lines[LineNo]=nullptr;
1293 if (pProfile->m_NoLines - LineNo > 1)
1294 {
1295 sal_uInt32 i, n;
1296
1297 memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1],
1298 (pProfile->m_NoLines - LineNo - 1) * sizeof(sal_Char *));
1299
1300 memset(&pProfile->m_Lines[pProfile->m_NoLines - 1],
1301 0,
1302 (pProfile->m_MaxLines - pProfile->m_NoLines) * sizeof(sal_Char*));
1303
1304 /* adjust line references */
1305 for (i = 0; i < pProfile->m_NoSections; i++)
1306 {
1307 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
1308
1309 if (pSec->m_Line > LineNo)
1310 pSec->m_Line--;
1311
1312 for (n = 0; n < pSec->m_NoEntries; n++)
1313 if (pSec->m_Entries[n].m_Line > LineNo)
1314 pSec->m_Entries[n].m_Line--;
1315 }
1316 }
1317 else
1318 {
1319 pProfile->m_Lines[LineNo] = nullptr;
1320 }
1321
1322 pProfile->m_NoLines--;
1323 }
1324 }
1325
setEntry(osl_TProfileImpl * pProfile,osl_TProfileSection * pSection,sal_uInt32 NoEntry,sal_uInt32 Line,sal_Char * Entry,sal_uInt32 Len)1326 static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection,
1327 sal_uInt32 NoEntry, sal_uInt32 Line,
1328 sal_Char* Entry, sal_uInt32 Len)
1329 {
1330 Entry = stripBlanks(Entry, &Len);
1331 pSection->m_Entries[NoEntry].m_Line = Line;
1332 pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line];
1333 pSection->m_Entries[NoEntry].m_Len = Len;
1334 }
1335
addEntry(osl_TProfileImpl * pProfile,osl_TProfileSection * pSection,int Line,sal_Char * Entry,sal_uInt32 Len)1336 static bool addEntry(osl_TProfileImpl* pProfile,
1337 osl_TProfileSection *pSection,
1338 int Line, sal_Char* Entry,
1339 sal_uInt32 Len)
1340 {
1341 if (pSection != nullptr)
1342 {
1343 if (pSection->m_NoEntries >= pSection->m_MaxEntries)
1344 {
1345 if (pSection->m_Entries == nullptr)
1346 {
1347 pSection->m_MaxEntries = ENTRIES_INI;
1348 pSection->m_Entries = static_cast<osl_TProfileEntry *>(malloc(
1349 pSection->m_MaxEntries * sizeof(osl_TProfileEntry)));
1350 }
1351 else
1352 {
1353 pSection->m_MaxEntries += ENTRIES_ADD;
1354 pSection->m_Entries = static_cast<osl_TProfileEntry *>(realloc(pSection->m_Entries,
1355 pSection->m_MaxEntries * sizeof(osl_TProfileEntry)));
1356 }
1357
1358 if (pSection->m_Entries == nullptr)
1359 {
1360 pSection->m_NoEntries = 0;
1361 pSection->m_MaxEntries = 0;
1362 return false;
1363 }
1364 }
1365
1366 pSection->m_NoEntries++;
1367
1368 Entry = stripBlanks(Entry, &Len);
1369 setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line,
1370 Entry, Len);
1371
1372 return true;
1373 }
1374
1375 return false;
1376 }
1377
removeEntry(osl_TProfileSection * pSection,sal_uInt32 NoEntry)1378 static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry)
1379 {
1380 if (NoEntry < pSection->m_NoEntries)
1381 {
1382 if (pSection->m_NoEntries - NoEntry > 1)
1383 {
1384 memmove(&pSection->m_Entries[NoEntry],
1385 &pSection->m_Entries[NoEntry + 1],
1386 (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry));
1387 pSection->m_Entries[pSection->m_NoEntries - 1].m_Line=0;
1388 pSection->m_Entries[pSection->m_NoEntries - 1].m_Offset=0;
1389 pSection->m_Entries[pSection->m_NoEntries - 1].m_Len=0;
1390 }
1391
1392 pSection->m_NoEntries--;
1393 }
1394
1395 }
1396
addSection(osl_TProfileImpl * pProfile,int Line,const sal_Char * Section,sal_uInt32 Len)1397 static bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len)
1398 {
1399 if (pProfile->m_NoSections >= pProfile->m_MaxSections)
1400 {
1401 if (pProfile->m_Sections == nullptr)
1402 {
1403 pProfile->m_MaxSections = SECTIONS_INI;
1404 pProfile->m_Sections = static_cast<osl_TProfileSection *>(calloc(pProfile->m_MaxSections, sizeof(osl_TProfileSection)));
1405 }
1406 else
1407 {
1408 unsigned int idx=0;
1409 unsigned int oldmax=pProfile->m_MaxSections;
1410
1411 pProfile->m_MaxSections += SECTIONS_ADD;
1412 pProfile->m_Sections = static_cast<osl_TProfileSection *>(realloc(pProfile->m_Sections,
1413 pProfile->m_MaxSections * sizeof(osl_TProfileSection)));
1414 for ( idx = oldmax ; idx < pProfile->m_MaxSections ; ++idx )
1415 {
1416 pProfile->m_Sections[idx].m_Entries=nullptr;
1417 }
1418 }
1419
1420 if (pProfile->m_Sections == nullptr)
1421 {
1422 pProfile->m_NoSections = 0;
1423 pProfile->m_MaxSections = 0;
1424 return false;
1425 }
1426 }
1427
1428 pProfile->m_NoSections++;
1429
1430 if ( pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries != nullptr )
1431 {
1432 free(pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries);
1433 }
1434 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = nullptr;
1435 pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries = 0;
1436 pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0;
1437
1438 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line;
1439 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line];
1440 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len;
1441
1442 return true;
1443 }
1444
removeSection(osl_TProfileImpl * pProfile,osl_TProfileSection * pSection)1445 static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection)
1446 {
1447 sal_uInt32 Section;
1448
1449 if ((Section = pSection - pProfile->m_Sections) < pProfile->m_NoSections)
1450 {
1451 free (pSection->m_Entries);
1452 pSection->m_Entries=nullptr;
1453 if (pProfile->m_NoSections - Section > 1)
1454 {
1455 memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1],
1456 (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection));
1457
1458 memset(&pProfile->m_Sections[pProfile->m_NoSections - 1],
1459 0,
1460 (pProfile->m_MaxSections - pProfile->m_NoSections) * sizeof(osl_TProfileSection));
1461 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = nullptr;
1462 }
1463 else
1464 {
1465 pSection->m_Entries = nullptr;
1466 }
1467
1468 pProfile->m_NoSections--;
1469 }
1470 }
1471
findEntry(osl_TProfileImpl * pProfile,const sal_Char * Section,const sal_Char * Entry,sal_uInt32 * pNoEntry)1472 static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile,
1473 const sal_Char* Section,
1474 const sal_Char* Entry,
1475 sal_uInt32 *pNoEntry)
1476 {
1477 static sal_uInt32 Sect = 0;
1478 sal_uInt32 i, n;
1479 sal_uInt32 Len;
1480 osl_TProfileSection* pSec=nullptr;
1481
1482 Len = strlen(Section);
1483
1484 n = Sect;
1485
1486 for (i = 0; i < pProfile->m_NoSections; i++)
1487 {
1488 n %= pProfile->m_NoSections;
1489 pSec = &pProfile->m_Sections[n];
1490 if ((Len == pSec->m_Len) &&
1491 (strncasecmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len)
1492 == 0))
1493 break;
1494 n++;
1495 }
1496
1497 Sect = n;
1498
1499 if (i < pProfile->m_NoSections)
1500 {
1501 Len = strlen(Entry);
1502
1503 *pNoEntry = pSec->m_NoEntries;
1504
1505 for (i = 0; i < pSec->m_NoEntries; i++)
1506 {
1507 const sal_Char* pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line]
1508 [pSec->m_Entries[i].m_Offset];
1509 if ((Len == pSec->m_Entries[i].m_Len) &&
1510 (strncasecmp(Entry, pStr, pSec->m_Entries[i].m_Len)
1511 == 0))
1512 {
1513 *pNoEntry = i;
1514 break;
1515 }
1516 }
1517 }
1518 else
1519 pSec = nullptr;
1520
1521 return pSec;
1522 }
1523
loadProfile(osl_TFile * pFile,osl_TProfileImpl * pProfile)1524 static bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile)
1525 {
1526 sal_uInt32 i;
1527 sal_Char* pStr;
1528 sal_Char* pChar;
1529
1530 sal_Char* pLine;
1531
1532 if ( !pFile )
1533 {
1534 return false;
1535 }
1536
1537 if ( !pProfile )
1538 {
1539 return false;
1540 }
1541
1542 pProfile->m_NoLines = 0;
1543 pProfile->m_NoSections = 0;
1544
1545 OSL_VERIFY(OslProfile_rewindFile(pFile, false));
1546
1547 while ( ( pLine=OslProfile_getLine(pFile) ) != nullptr )
1548 {
1549 sal_Char* bWasAdded = addLine( pProfile, pLine );
1550 free( pLine );
1551 SAL_WARN_IF(!bWasAdded, "sal.osl", "addLine( pProfile, pLine ) ==> false");
1552 if ( ! bWasAdded )
1553 return false;
1554 }
1555
1556 for (i = 0; i < pProfile->m_NoLines; i++)
1557 {
1558 pStr = stripBlanks(pProfile->m_Lines[i], nullptr);
1559
1560 if ((*pStr == '\0') || (*pStr == ';'))
1561 continue;
1562
1563 if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == nullptr) ||
1564 ((pChar - pStr) <= 2))
1565 {
1566 /* insert entry */
1567
1568 if (pProfile->m_NoSections < 1)
1569 continue;
1570
1571 if ((pChar = strchr(pStr, '=')) == nullptr)
1572 pChar = pStr + strlen(pStr);
1573
1574 if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1],
1575 i, pStr, pChar - pStr))
1576 {
1577 SAL_WARN("sal.osl", "Adding entry => false");
1578 continue;
1579 }
1580
1581 }
1582 else
1583 {
1584 /* new section */
1585
1586 if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1))
1587 {
1588 SAL_WARN("sal.osl", "Adding section => false");
1589 continue;
1590 }
1591
1592 }
1593 }
1594
1595 return true;
1596 }
1597
storeProfile(osl_TProfileImpl * pProfile,bool bCleanup)1598 static bool storeProfile(osl_TProfileImpl* pProfile, bool bCleanup)
1599 {
1600 if (pProfile->m_Lines != nullptr)
1601 {
1602 if (pProfile->m_Flags & FLG_MODIFIED)
1603 {
1604 sal_uInt32 i;
1605
1606 osl_TFile* pTmpFile = osl_openTmpProfileImpl(pProfile);
1607
1608 if ( pTmpFile == nullptr )
1609 {
1610 return false;
1611 }
1612
1613 OSL_VERIFY(OslProfile_rewindFile(pTmpFile, true));
1614
1615 for ( i = 0 ; i < pProfile->m_NoLines ; i++ )
1616 {
1617 OSL_VERIFY(OslProfile_putLine(pTmpFile, pProfile->m_Lines[i]));
1618 }
1619
1620 if ( ! writeProfileImpl(pTmpFile) )
1621 {
1622 if ( pTmpFile->m_pWriteBuf != nullptr )
1623 {
1624 free(pTmpFile->m_pWriteBuf);
1625 }
1626
1627 pTmpFile->m_pWriteBuf=nullptr;
1628 pTmpFile->m_nWriteBufLen=0;
1629 pTmpFile->m_nWriteBufFree=0;
1630
1631 closeFileImpl(pTmpFile,pProfile->m_Flags);
1632
1633 return false;
1634 }
1635
1636 pProfile->m_Flags &= ~FLG_MODIFIED;
1637
1638 closeFileImpl(pProfile->m_pFile,pProfile->m_Flags);
1639 closeFileImpl(pTmpFile,pProfile->m_Flags);
1640
1641 osl_ProfileSwapProfileNames(pProfile);
1642
1643 pProfile->m_pFile = openFileImpl(pProfile->m_FileName,pProfile->m_Flags);
1644
1645 }
1646
1647 if (bCleanup)
1648 {
1649 while (pProfile->m_NoLines > 0)
1650 removeLine(pProfile, pProfile->m_NoLines - 1);
1651
1652 free(pProfile->m_Lines);
1653 pProfile->m_Lines = nullptr;
1654 pProfile->m_NoLines = 0;
1655 pProfile->m_MaxLines = 0;
1656
1657 while (pProfile->m_NoSections > 0)
1658 removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]);
1659
1660 free(pProfile->m_Sections);
1661 pProfile->m_Sections = nullptr;
1662 pProfile->m_NoSections = 0;
1663 pProfile->m_MaxSections = 0;
1664 }
1665 }
1666
1667 return true;
1668 }
1669
osl_openTmpProfileImpl(osl_TProfileImpl * pProfile)1670 static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl* pProfile)
1671 {
1672 osl_TFile* pFile=nullptr;
1673 sal_Char const * const pszExtension = "tmp";
1674 sal_Char pszTmpName[PATH_MAX];
1675 oslProfileOption PFlags=0;
1676
1677 pszTmpName[0] = '\0';
1678
1679 /* generate tmp profilename */
1680 osl_ProfileGenerateExtension(pProfile->m_FileName, pszExtension, pszTmpName, PATH_MAX);
1681
1682 if ( pszTmpName[0] == 0 )
1683 {
1684 return nullptr;
1685 }
1686
1687 if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) )
1688 {
1689 PFlags |= osl_Profile_WRITELOCK;
1690 }
1691
1692 /* open this file */
1693 pFile = openFileImpl(pszTmpName,pProfile->m_Flags | PFlags);
1694
1695 /* return new pFile */
1696 return pFile;
1697 }
1698
osl_ProfileSwapProfileNames(osl_TProfileImpl * pProfile)1699 static bool osl_ProfileSwapProfileNames(osl_TProfileImpl* pProfile)
1700 {
1701 sal_Char pszBakFile[PATH_MAX];
1702 sal_Char pszTmpFile[PATH_MAX];
1703
1704 pszBakFile[0] = '\0';
1705 pszTmpFile[0] = '\0';
1706
1707 osl_ProfileGenerateExtension(pProfile->m_FileName, "bak", pszBakFile, PATH_MAX);
1708 osl_ProfileGenerateExtension(pProfile->m_FileName, "tmp", pszTmpFile, PATH_MAX);
1709
1710 /* unlink bak */
1711 unlink( pszBakFile );
1712
1713 // Rename ini -> bak, then tmp -> ini:
1714 bool result = rename( pProfile->m_FileName, pszBakFile ) == 0;
1715 if (!result)
1716 {
1717 int e = errno;
1718 SAL_INFO("sal.file", "rename(" << pProfile->m_FileName << "," << pszBakFile << "): " << UnixErrnoString(e));
1719 }
1720 else
1721 {
1722 SAL_INFO("sal.file", "rename(" << pProfile->m_FileName << "," << pszBakFile << "): OK");
1723 result = rename( pszTmpFile, pProfile->m_FileName ) == 0;
1724 if (!result)
1725 {
1726 int e = errno;
1727 SAL_INFO("sal.file", "rename(" << pszTmpFile << "," << pProfile->m_FileName << "): " << UnixErrnoString(e));
1728 }
1729 else
1730 {
1731 SAL_INFO("sal.file", "rename(" << pszTmpFile << "," << pProfile->m_FileName << "): OK");
1732 }
1733 }
1734 return result;
1735 }
1736
osl_ProfileGenerateExtension(const sal_Char * pszFileName,const sal_Char * pszExtension,sal_Char * pszTmpName,int BufferMaxLen)1737 static void osl_ProfileGenerateExtension(const sal_Char* pszFileName, const sal_Char* pszExtension, sal_Char* pszTmpName, int BufferMaxLen)
1738 {
1739 sal_Char* cursor = pszTmpName;
1740 int len;
1741
1742 /* concatenate filename + "." + extension, limited to the size of the
1743 * output buffer; in case of overrun, data is truncated at the end...
1744 * and the result is always 0-terminated.
1745 */
1746 len = strlen(pszFileName);
1747 if(len < BufferMaxLen)
1748 {
1749 memcpy(cursor, pszFileName, len);
1750 cursor += len;
1751 BufferMaxLen -= len;
1752 }
1753 else
1754 {
1755 memcpy(cursor, pszFileName, BufferMaxLen - 1);
1756 cursor += BufferMaxLen - 1;
1757 BufferMaxLen = 1;
1758 }
1759 if(BufferMaxLen > 1)
1760 {
1761 *cursor++ = '.';
1762 BufferMaxLen -= 1;
1763 }
1764 len = strlen(pszExtension);
1765 if(len < BufferMaxLen)
1766 {
1767 memcpy(cursor, pszExtension, len);
1768 cursor += len;
1769 }
1770 else
1771 {
1772 memcpy(cursor, pszExtension, BufferMaxLen - 1);
1773 cursor += BufferMaxLen - 1;
1774 }
1775 *cursor = 0;
1776 }
1777
acquireProfile(oslProfile Profile,bool bWriteable)1778 static osl_TProfileImpl* acquireProfile(oslProfile Profile, bool bWriteable)
1779 {
1780 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
1781 oslProfileOption PFlags=0;
1782
1783 if ( bWriteable )
1784 {
1785 PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK;
1786 }
1787 else
1788 {
1789 PFlags = osl_Profile_DEFAULT;
1790 }
1791
1792 if (pProfile == nullptr)
1793 {
1794 if ( ( pProfile = static_cast<osl_TProfileImpl*>(osl_openProfile(nullptr, PFlags )) ) != nullptr )
1795 {
1796 pProfile->m_Flags |= FLG_AUTOOPEN;
1797 }
1798 }
1799 else
1800 {
1801 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
1802 {
1803 if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE )))
1804 {
1805 osl_TStamp Stamp;
1806
1807 if (! (pProfile->m_pFile = openFileImpl(pProfile->m_FileName, pProfile->m_Flags | PFlags )))
1808 return nullptr;
1809
1810 Stamp = OslProfile_getFileStamp(pProfile->m_pFile);
1811
1812 if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp)))
1813 {
1814 pProfile->m_Stamp = Stamp;
1815 bool bRet = loadProfile(pProfile->m_pFile, pProfile);
1816 SAL_WARN_IF(!bRet, "sal.osl", "loadProfile(pProfile->m_pFile, pProfile) ==> false");
1817 }
1818 }
1819 else
1820 {
1821 /* A readlock file could not be written */
1822 if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable)
1823 {
1824 return nullptr;
1825 }
1826 }
1827 }
1828 }
1829
1830 return pProfile;
1831 }
1832
releaseProfile(osl_TProfileImpl * pProfile)1833 static bool releaseProfile(osl_TProfileImpl* pProfile)
1834 {
1835 if ( pProfile == nullptr )
1836 {
1837 return false;
1838 }
1839
1840 if (pProfile->m_Flags & FLG_AUTOOPEN)
1841 {
1842 return osl_closeProfile(static_cast<oslProfile>(pProfile));
1843 }
1844
1845 if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE )))
1846 {
1847 if (pProfile->m_Flags & FLG_MODIFIED)
1848 {
1849 bool bRet = storeProfile(pProfile, false);
1850 SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pProfile, false) ==> false");
1851 }
1852
1853 closeFileImpl(pProfile->m_pFile,pProfile->m_Flags);
1854 pProfile->m_pFile = nullptr;
1855 }
1856
1857 return true;
1858 }
1859
1860 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1861