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