diff options
Diffstat (limited to '')
-rw-r--r-- | sal/osl/unx/profile.cxx | 1866 |
1 files changed, 1866 insertions, 0 deletions
diff --git a/sal/osl/unx/profile.cxx b/sal/osl/unx/profile.cxx new file mode 100644 index 000000000..354fe626f --- /dev/null +++ b/sal/osl/unx/profile.cxx @@ -0,0 +1,1866 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "system.hxx" +#include "readwrite_helper.hxx" +#include "file_url.hxx" +#include "unixerrnostring.hxx" + +#include <osl/diagnose.h> +#include <osl/profile.h> +#include <osl/process.h> +#include <osl/thread.h> +#include <rtl/alloc.h> +#include <sal/log.hxx> + +#define LINES_INI 32 +#define LINES_ADD 10 +#define SECTIONS_INI 5 +#define SECTIONS_ADD 3 +#define ENTRIES_INI 5 +#define ENTRIES_ADD 3 + +#define STR_INI_BOOLYES "yes" +#define STR_INI_BOOLON "on" +#define STR_INI_BOOLONE "1" +#define STR_INI_BOOLNO "no" +#define STR_INI_BOOLOFF "off" +#define STR_INI_BOOLZERO "0" + +#define FLG_USER 0x00FF +#define FLG_AUTOOPEN 0x0100 +#define FLG_MODIFIED 0x0200 + +#define DEFAULT_PMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) + +typedef time_t osl_TStamp; + +namespace { + +enum osl_TLockMode +{ + un_lock, read_lock, write_lock +}; + +struct osl_TFile +{ + int m_Handle; + char* m_pReadPtr; + char m_ReadBuf[512]; + char* m_pWriteBuf; + sal_uInt32 m_nWriteBufLen; + sal_uInt32 m_nWriteBufFree; +}; + +struct osl_TProfileEntry +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; +}; + +struct osl_TProfileSection +{ + sal_uInt32 m_Line; + sal_uInt32 m_Offset; + sal_uInt32 m_Len; + sal_uInt32 m_NoEntries; + sal_uInt32 m_MaxEntries; + osl_TProfileEntry* m_Entries; +}; + +/* Profile-data structure hidden behind oslProfile: */ +struct osl_TProfileImpl +{ + sal_uInt32 m_Flags; + osl_TFile* m_pFile; + osl_TStamp m_Stamp; + char m_FileName[PATH_MAX + 1]; + sal_uInt32 m_NoLines; + sal_uInt32 m_MaxLines; + sal_uInt32 m_NoSections; + sal_uInt32 m_MaxSections; + char** m_Lines; + osl_TProfileSection* m_Sections; + pthread_mutex_t m_AccessLock; + bool m_bIsValid; +}; + +} + +static osl_TFile* openFileImpl(const char* pszFilename, oslProfileOption ProfileFlags); +static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags); +static bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode); +static bool OslProfile_rewindFile(osl_TFile* pFile, bool bTruncate); +static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile); + +static char* OslProfile_getLine(osl_TFile* pFile); +static bool OslProfile_putLine(osl_TFile* pFile, const char *pszLine); +static char* stripBlanks(char* String, sal_uInt32* pLen); +static char* addLine(osl_TProfileImpl* pProfile, const char* Line); +static char* insertLine(osl_TProfileImpl* pProfile, const char* Line, sal_uInt32 LineNo); +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo); +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + char* Entry, sal_uInt32 Len); +static bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection, + int Line, char* Entry, sal_uInt32 Len); +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry); +static bool addSection(osl_TProfileImpl* pProfile, int Line, const char* Section, sal_uInt32 Len); +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection); +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const char* Section, + const char* Entry, sal_uInt32 *pNoEntry); +static bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile); +static bool storeProfile(osl_TProfileImpl* pProfile, bool bCleanup); +static osl_TProfileImpl* acquireProfile(oslProfile Profile, bool bWriteable); +static bool releaseProfile(osl_TProfileImpl* pProfile); + +static bool writeProfileImpl (osl_TFile* pFile); +static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl*); +static bool osl_ProfileSwapProfileNames(osl_TProfileImpl*); +static void osl_ProfileGenerateExtension(const char* pszFileName, const char* pszExtension, char* pszTmpName, int BufferMaxLen); +static oslProfile osl_psz_openProfile(const char *pszProfileName, oslProfileOption Flags); + +oslProfile SAL_CALL osl_openProfile(rtl_uString *ustrProfileName, oslProfileOption Options) +{ + char profilePath[PATH_MAX] = ""; + return + (ustrProfileName == nullptr + || ustrProfileName->buffer[0] == 0 + || (FileURLToPath(profilePath, PATH_MAX, ustrProfileName) + == osl_File_E_None)) + ? osl_psz_openProfile(profilePath, Options) + : nullptr; +} + +static oslProfile osl_psz_openProfile(const char *pszProfileName, oslProfileOption Flags) +{ + osl_TFile* pFile; + osl_TProfileImpl* pProfile; + bool bRet = false; + + if ( ( pFile = openFileImpl(pszProfileName, Flags ) ) == nullptr ) + { + return nullptr; + } + + pProfile = static_cast<osl_TProfileImpl*>(calloc(1, sizeof(osl_TProfileImpl))); + + if ( pProfile == nullptr ) + { + closeFileImpl(pFile, Flags); + return nullptr; + } + + pProfile->m_Flags = Flags & FLG_USER; + + if ( Flags & ( osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) ) + { + pProfile->m_pFile = pFile; + } + + pthread_mutex_init(&(pProfile->m_AccessLock),PTHREAD_MUTEXATTR_DEFAULT); + pProfile->m_bIsValid = true; + + pProfile->m_Stamp = OslProfile_getFileStamp(pFile); + bRet=loadProfile(pFile, pProfile); + bRet &= realpath(pszProfileName, pProfile->m_FileName) != nullptr; + SAL_WARN_IF(!bRet, "sal.osl", "realpath(pszProfileName, pProfile->m_FileName) != NULL ==> false"); + + if (pProfile->m_pFile == nullptr) + closeFileImpl(pFile,pProfile->m_Flags); + + // coverity[leaked_storage] - pFile is not leaked + return pProfile; +} + +sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile); + osl_TProfileImpl* pTmpProfile; + + if ( Profile == nullptr ) + { + return false; + } + + pthread_mutex_lock(&(pProfile->m_AccessLock)); + + if ( !pProfile->m_bIsValid ) + { + SAL_WARN("sal.osl", "!pProfile->m_bIsValid"); + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + + return false; + } + + pProfile->m_bIsValid = false; + + if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) && ( pProfile->m_Flags & FLG_MODIFIED ) ) + { + pTmpProfile = acquireProfile(Profile, true); + + if ( pTmpProfile != nullptr ) + { + bool bRet = storeProfile(pTmpProfile, true); + SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pTmpProfile, true) ==> false"); + } + } + else + { + pTmpProfile = acquireProfile(Profile, false); + } + + if ( pTmpProfile == nullptr ) + { + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + + SAL_INFO("sal.osl", "Out osl_closeProfile [pProfile==0]"); + return false; + } + + pProfile = pTmpProfile; + + if (pProfile->m_pFile != nullptr) + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + + pProfile->m_pFile = nullptr; + pProfile->m_FileName[0] = '\0'; + + /* release whole profile data types memory */ + if ( pProfile->m_NoLines > 0) + { + unsigned int idx=0; + if ( pProfile->m_Lines != nullptr ) + { + for ( idx = 0 ; idx < pProfile->m_NoLines ; ++idx) + { + if ( pProfile->m_Lines[idx] != nullptr ) + { + free(pProfile->m_Lines[idx]); + pProfile->m_Lines[idx]=nullptr; + } + } + free(pProfile->m_Lines); + pProfile->m_Lines=nullptr; + } + if ( pProfile->m_Sections != nullptr ) + { + /*osl_TProfileSection* pSections=pProfile->m_Sections;*/ + for ( idx = 0 ; idx < pProfile->m_NoSections ; ++idx ) + { + if ( pProfile->m_Sections[idx].m_Entries != nullptr ) + { + free(pProfile->m_Sections[idx].m_Entries); + pProfile->m_Sections[idx].m_Entries=nullptr; + } + } + free(pProfile->m_Sections); + pProfile->m_Sections=nullptr; + } + } + + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + + pthread_mutex_destroy(&(pProfile->m_AccessLock)); + + free(pProfile); + + return true; +} + +sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile) +{ + osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile); + osl_TFile* pFile; + bool bRet = false; + + if ( pProfile == nullptr ) + { + return false; + } + + pthread_mutex_lock(&(pProfile->m_AccessLock)); + + if ( !pProfile->m_bIsValid ) + { + SAL_WARN_IF(!pProfile->m_bIsValid, "sal.osl", "!pProfile->m_bIsValid"); + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + return false; + } + + pFile = pProfile->m_pFile; + if ( pFile == nullptr || pFile->m_Handle < 0 ) + { + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + + return false; + } + + if ( pProfile->m_Flags & FLG_MODIFIED ) + { + bRet = storeProfile(pProfile, false); + SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pProfile, false) ==> false"); + } + + pthread_mutex_unlock(&(pProfile->m_AccessLock)); + return bRet; +} + +static bool writeProfileImpl(osl_TFile* pFile) +{ + if ( pFile == nullptr || pFile->m_Handle < 0 || pFile->m_pWriteBuf == nullptr ) + { + return false; + } + + SAL_WARN_IF( + (strlen(pFile->m_pWriteBuf) + != pFile->m_nWriteBufLen - pFile->m_nWriteBufFree), + "sal.osl", + strlen(pFile->m_pWriteBuf) << " != " + << (pFile->m_nWriteBufLen - pFile->m_nWriteBufFree)); + + if ( !safeWrite(pFile->m_Handle, pFile->m_pWriteBuf, pFile->m_nWriteBufLen - pFile->m_nWriteBufFree) ) + { + SAL_INFO("sal.osl", "write failed: " << UnixErrnoString(errno)); + return false; + } + + free(pFile->m_pWriteBuf); + pFile->m_pWriteBuf=nullptr; + pFile->m_nWriteBufLen=0; + pFile->m_nWriteBufFree=0; + + return true; +} + +sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile, + const char* pszSection, + const char* pszEntry, + char* pszString, + sal_uInt32 MaxLen, + const char* pszDefault) +{ + sal_uInt32 NoEntry; + char* pStr=nullptr; + osl_TProfileImpl* pProfile=nullptr; + osl_TProfileImpl* pTmpProfile=nullptr; + bool bRet = false; + + pTmpProfile = static_cast<osl_TProfileImpl*>(Profile); + + if ( pTmpProfile == nullptr ) + { + return false; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( !pTmpProfile->m_bIsValid ) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return false; + } + + pProfile = acquireProfile(Profile, false); + + if ( pProfile == nullptr ) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return false; + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + osl_TProfileSection* pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry); + if ((pSec != nullptr) && + (NoEntry < pSec->m_NoEntries) && + ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line], + '=')) != nullptr)) + { + pStr++; + } + else + { + pStr=const_cast<char*>(pszDefault); + } + + if ( pStr != nullptr ) + { + pStr = stripBlanks(pStr, nullptr); + MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr); + pStr = stripBlanks(pStr, &MaxLen); + strncpy(pszString, pStr, MaxLen); + pszString[MaxLen] = '\0'; + } + } + else + { /* not implemented */ } + + bRet=releaseProfile(pProfile); + SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false"); + + if ( pStr == nullptr ) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return false; + } + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return true; +} + +sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile, + const char* pszSection, + const char* pszEntry, + sal_Bool Default) +{ + char Line[32]; + Line[0] = '\0'; + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + if ((strcasecmp(Line, STR_INI_BOOLYES) == 0) || + (strcasecmp(Line, STR_INI_BOOLON) == 0) || + (strcasecmp(Line, STR_INI_BOOLONE) == 0)) + Default = true; + else + if ((strcasecmp(Line, STR_INI_BOOLNO) == 0) || + (strcasecmp(Line, STR_INI_BOOLOFF) == 0) || + (strcasecmp(Line, STR_INI_BOOLZERO) == 0)) + Default = false; + } + + return Default; +} + +sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile, + const char* pszSection, + const char* pszEntry, + sal_uInt32 FirstId, + const char* Strings[], + sal_uInt32 Default) +{ + sal_uInt32 i; + char Line[256]; + Line[0] = '\0'; + + if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), "")) + { + i = 0; + while (Strings[i] != nullptr) + { + if (strcasecmp(Line, Strings[i]) == 0) + { + Default = i + FirstId; + break; + } + i++; + } + } + + return Default; +} + +sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile, + const char* pszSection, + const char* pszEntry, + const char* pszString) +{ + bool bRet = false; + sal_uInt32 NoEntry; + char* pStr; + char* Line = nullptr; + osl_TProfileImpl* pProfile = nullptr; + osl_TProfileImpl* pTmpProfile = static_cast<osl_TProfileImpl*>(Profile); + + if ( pTmpProfile == nullptr ) + { + return false; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( !pTmpProfile->m_bIsValid ) + { + SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid"); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return false; + } + + pProfile=acquireProfile(Profile, true); + + if (pProfile == nullptr) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return false; + } + + Line = static_cast<char*>(malloc(strlen(pszEntry)+strlen(pszString)+48)); + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + osl_TProfileSection* pSec; + if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == nullptr) + { + Line[0] = '\0'; + addLine(pProfile, Line); + + Line[0] = '['; + strcpy(&Line[1], pszSection); + Line[1 + strlen(pszSection)] = ']'; + Line[2 + strlen(pszSection)] = '\0'; + + pStr = addLine(pProfile, Line); + if ((pStr == nullptr) || + (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection)))) + { + bRet=releaseProfile(pProfile); + SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false"); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + free(Line); + return false; + } + + pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1]; + NoEntry = pSec->m_NoEntries; + } + + Line[0] = '\0'; + strcpy(&Line[0], pszEntry); + Line[0 + strlen(pszEntry)] = '='; + strcpy(&Line[1 + strlen(pszEntry)], pszString); + + if (NoEntry >= pSec->m_NoEntries) + { + sal_uInt32 i; + if (pSec->m_NoEntries > 0) + i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1; + else + i = pSec->m_Line + 1; + + pStr = insertLine(pProfile, Line, i); + if ((pStr == nullptr) || + (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry)))) + { + bRet=releaseProfile(pProfile); + SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false"); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + free(Line); + + return false; + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + else + { + sal_uInt32 i = pSec->m_Entries[NoEntry].m_Line; + free(pProfile->m_Lines[i]); + pProfile->m_Lines[i] = strdup(Line); + setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry)); + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else { + /* not implemented */ + } + + bRet = releaseProfile(pProfile); + SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false"); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + if ( Line!= nullptr ) + { + free(Line); + } + + return bRet; +} + +sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile, + const char* pszSection, + const char* pszEntry, + sal_Bool Value) +{ + bool bRet = false; + + if (Value) + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE); + else + bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO); + + return bRet; +} + +sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile, + const char* pszSection, + const char* pszEntry, + sal_uInt32 FirstId, + const char* Strings[], + sal_uInt32 Value) +{ + int i, n = 0; + bool bRet = false; + + while (Strings[n] != nullptr) + ++n; + + if ((i = Value - FirstId) >= n) + bRet = false; + else + bRet = osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]); + + return bRet; +} + +sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile, + const char *pszSection, + const char *pszEntry) +{ + sal_uInt32 NoEntry; + osl_TProfileImpl* pProfile = nullptr; + osl_TProfileImpl* pTmpProfile = nullptr; + bool bRet = false; + + pTmpProfile = static_cast<osl_TProfileImpl*>(Profile); + + if ( pTmpProfile == nullptr ) + { + return false; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( !pTmpProfile->m_bIsValid ) + { + SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid"); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + return false; + } + + pProfile = acquireProfile(Profile, true); + + if (pProfile == nullptr) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return false; + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + osl_TProfileSection* pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry); + if ((pSec != nullptr) && + (NoEntry < pSec->m_NoEntries)) + { + removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line); + removeEntry(pSec, NoEntry); + if (pSec->m_NoEntries == 0) + { + removeLine(pProfile, pSec->m_Line); + + /* remove any empty separation line */ + if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0')) + removeLine(pProfile, pSec->m_Line - 1); + + removeSection(pProfile, pSec); + } + + pProfile->m_Flags |= FLG_MODIFIED; + } + } + else + { /* not implemented */ } + + bRet = releaseProfile(pProfile); + SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false"); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return bRet; +} + +sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile, + const char *pszSection, + char* pszBuffer, + sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + sal_uInt32 NoEntry; + osl_TProfileImpl* pProfile = nullptr; + osl_TProfileImpl* pTmpProfile = nullptr; + bool bRet = false; + + pTmpProfile = static_cast<osl_TProfileImpl*>(Profile); + + if ( pTmpProfile == nullptr ) + { + return 0; + + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( !pTmpProfile->m_bIsValid ) + { + SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid"); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return 0; + } + + pProfile = acquireProfile(Profile, false); + + if (pProfile == nullptr) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return 0; + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + osl_TProfileSection* pSec; + if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != nullptr) + { + if (MaxLen != 0) + { + for (i = 0; i < pSec->m_NoEntries; i++) + { + if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len); + n += pSec->m_Entries[i].m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pSec->m_NoEntries; i++) + n += pSec->m_Entries[i].m_Len + 1; + + n += 1; + } + } + else + n = 0; + } + else { + /* not implemented */ + } + + bRet=releaseProfile(pProfile); + SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false"); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return n; +} + +sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile, + char* pszBuffer, + sal_uInt32 MaxLen) +{ + sal_uInt32 i, n = 0; + osl_TProfileImpl* pProfile = nullptr; + osl_TProfileImpl* pTmpProfile = nullptr; + bool bRet = false; + + pTmpProfile = static_cast<osl_TProfileImpl*>(Profile); + + if ( pTmpProfile == nullptr ) + { + return 0; + } + + pthread_mutex_lock(&(pTmpProfile->m_AccessLock)); + + if ( !pTmpProfile->m_bIsValid ) + { + SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid"); + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return 0; + } + + pProfile = acquireProfile(Profile, false); + + if (pProfile == nullptr) + { + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return 0; + } + + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (MaxLen != 0) + { + for (i = 0; i < pProfile->m_NoSections; i++) + { + osl_TProfileSection* pSec = &pProfile->m_Sections[i]; + + if ((n + pSec->m_Len + 1) < MaxLen) + { + strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], + pSec->m_Len); + n += pSec->m_Len; + pszBuffer[n++] = '\0'; + } + else + break; + } + + pszBuffer[n++] = '\0'; + } + else + { + for (i = 0; i < pProfile->m_NoSections; i++) + n += pProfile->m_Sections[i].m_Len + 1; + + n += 1; + } + } + else + { /* not implemented */ } + + bRet=releaseProfile(pProfile); + SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false"); + + pthread_mutex_unlock(&(pTmpProfile->m_AccessLock)); + + return n; +} + +static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile) +{ + struct stat status; + + if ( (pFile->m_Handle < 0) || (fstat(pFile->m_Handle, &status) < 0) ) + { + return 0; + } + + return status.st_mtime; +} + +static bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode) +{ + struct flock lock; + static bool const bLockingDisabled = getenv( "STAR_PROFILE_LOCKING_DISABLED" ) != nullptr; + + if (pFile->m_Handle < 0) + { + return false; + } + + if ( bLockingDisabled ) + { + return true; + } + + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + switch (eMode) + { + case un_lock: + lock.l_type = F_UNLCK; + break; + + case read_lock: + lock.l_type = F_RDLCK; + break; + + case write_lock: + lock.l_type = F_WRLCK; + break; + } + +#ifndef MACOSX + if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 ) +#else + /* Mac OSX will return ENOTSUP for webdav drives so we should ignore it */ + if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 && errno != ENOTSUP ) +#endif + { + SAL_INFO("sal.osl", "fcntl failed: " << UnixErrnoString(errno)); + return false; + } + + return true; +} + +static osl_TFile* openFileImpl(const char* pszFilename, oslProfileOption ProfileFlags ) +{ + int Flags; + osl_TFile* pFile = static_cast<osl_TFile*>(calloc(1, sizeof(osl_TFile))); + bool bWriteable = false; + + if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) ) + { + bWriteable = true; + } + + if (! bWriteable) + { + pFile->m_Handle = open(pszFilename, O_RDONLY); + + if (pFile->m_Handle == -1) + { + int e = errno; + SAL_INFO("sal.file", "open(" << pszFilename << ",O_RDONLY): " << UnixErrnoString(e)); + } + else + SAL_INFO("sal.file", "open(" << pszFilename << ",O_RDONLY) => " << pFile->m_Handle); + + /* mfe: argghh!!! do not check if the file could be opened */ + /* default mode expects it that way!!! */ + } + else + { + if (((pFile->m_Handle = open(pszFilename, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PMODE)) < 0) && + ((pFile->m_Handle = open(pszFilename, O_RDWR)) < 0)) + { + int e = errno; + SAL_INFO("sal.file", "open(" << pszFilename << ",...): " << UnixErrnoString(e)); + free(pFile); + return nullptr; + } + else + SAL_INFO("sal.file", "open(" << pszFilename << ",...) => " << pFile->m_Handle); + } + + /* set close-on-exec flag */ + if ((Flags = fcntl(pFile->m_Handle, F_GETFD, 0)) != -1) + { + Flags |= FD_CLOEXEC; + int e = fcntl(pFile->m_Handle, F_SETFD, Flags); + SAL_INFO_IF( + e != 0, "sal.osl", + "fcntl to set FD_CLOEXEC failed for " << pszFilename); + } + + pFile->m_pWriteBuf=nullptr; + pFile->m_nWriteBufFree=0; + pFile->m_nWriteBufLen=0; + + if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) ) + { + OslProfile_lockFile(pFile, bWriteable ? write_lock : read_lock); + } + + return pFile; +} + +static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags) +{ + osl_TStamp stamp = 0; + + if ( pFile == nullptr ) + { + return stamp; + } + + if ( pFile->m_Handle >= 0 ) + { + stamp = OslProfile_getFileStamp(pFile); + + if ( Flags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) ) + { + OslProfile_lockFile(pFile, un_lock); + } + + close(pFile->m_Handle); + SAL_INFO("sal.file", "close(" << pFile->m_Handle << ")"); + pFile->m_Handle = -1; + } + + if ( pFile->m_pWriteBuf ) + { + free(pFile->m_pWriteBuf); + } + + free(pFile); + + return stamp; +} + +static bool OslProfile_rewindFile(osl_TFile* pFile, bool bTruncate) +{ + bool bRet = true; + + if (pFile->m_Handle >= 0) + { + pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + + bRet = (lseek(pFile->m_Handle, SEEK_SET, 0) == 0); + + if (bTruncate) + { + bRet &= (ftruncate(pFile->m_Handle, 0) == 0); + } + + } + + return bRet; +} + +static char* OslProfile_getLine(osl_TFile* pFile) +{ + int Max, Free, nLineBytes = 0; + char* pChr; + char* pLine = nullptr; + char* pNewLine; + + if ( pFile == nullptr ) + { + return nullptr; + } + + if (pFile->m_Handle < 0) + return nullptr; + + do + { + int Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf); + + if (Bytes <= 1) + { + /* refill buffer */ + memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes); + pFile->m_pReadPtr = pFile->m_ReadBuf; + + Free = sizeof(pFile->m_ReadBuf) - Bytes; + + if ((Max = read(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free)) < 0) + { + SAL_INFO("sal.osl", "read failed: " << UnixErrnoString(errno)); + + if( pLine ) + free( pLine ); + pLine = nullptr; + break; + } + + if (Max < Free) + { + if ((Max == 0) && ! pLine) + break; + + pFile->m_ReadBuf[Bytes + Max] = '\0'; + } + } + + for (pChr = pFile->m_pReadPtr; + (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') && + (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)); + pChr++); + + Max = pChr - pFile->m_pReadPtr; + pNewLine = static_cast<char*>(malloc( nLineBytes + Max + 1 )); + if( pLine ) + { + memcpy( pNewLine, pLine, nLineBytes ); + free( pLine ); + } + memcpy(pNewLine+nLineBytes, pFile->m_pReadPtr, Max); + nLineBytes += Max; + pNewLine[ nLineBytes ] = 0; + pLine = pNewLine; + + if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1)) + { + if (*pChr != '\0') + { + if ((pChr[0] == '\r') && (pChr[1] == '\n')) + pChr += 2; + else + pChr += 1; + } + + if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) && + (*pChr == '\0')) + pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf); + + /* setting Max to -1 indicates terminating read loop */ + Max = -1; + } + + pFile->m_pReadPtr = pChr; + } + while (Max > 0) ; + + return pLine; +} + +static bool OslProfile_putLine(osl_TFile* pFile, const char *pszLine) +{ + unsigned int Len = strlen(pszLine); + + if ( pFile == nullptr || pFile->m_Handle < 0 ) + { + return false; + } + + if ( pFile->m_pWriteBuf == nullptr ) + { + pFile->m_pWriteBuf = static_cast<char*>(malloc(Len+3)); + pFile->m_nWriteBufLen = Len+3; + pFile->m_nWriteBufFree = Len+3; + } + else + { + if ( pFile->m_nWriteBufFree <= Len + 3 ) + { + char* pTmp; + + pTmp=static_cast<char*>(realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) )); + if ( pTmp == nullptr ) + { + return false; + } + pFile->m_pWriteBuf = pTmp; + pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len ); + pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2; + memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree); + } + } + + memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1); + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\n'; + pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\0'; + + pFile->m_nWriteBufFree-=Len+1; + + return true; +} + +static char* stripBlanks(char* String, sal_uInt32* pLen) +{ + if ( ( pLen != nullptr ) && ( *pLen != 0 ) ) + { + while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t')) + (*pLen)--; + + while ( (*String == ' ') || (*String == '\t') ) + { + String++; + (*pLen)--; + } + } + else + while ( (*String == ' ') || (*String == '\t') ) + String++; + + return String; +} + +static char* addLine(osl_TProfileImpl* pProfile, const char* Line) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == nullptr) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = static_cast<char **>(calloc(pProfile->m_MaxLines, sizeof(char *))); + } + else + { + unsigned int idx=0; + unsigned int oldmax=pProfile->m_MaxLines; + + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = static_cast<char **>(realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(char *))); + for ( idx = oldmax ; idx < pProfile->m_MaxLines ; ++idx ) + { + pProfile->m_Lines[idx]=nullptr; + } + } + } + if (pProfile->m_Lines == nullptr) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return nullptr; + } + + if ( pProfile->m_Lines[pProfile->m_NoLines] != nullptr ) + { + free(pProfile->m_Lines[pProfile->m_NoLines]); + } + pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line); + + return pProfile->m_Lines[pProfile->m_NoLines - 1]; +} + +static char* insertLine(osl_TProfileImpl* pProfile, const char* Line, sal_uInt32 LineNo) +{ + if (pProfile->m_NoLines >= pProfile->m_MaxLines) + { + if (pProfile->m_Lines == nullptr) + { + pProfile->m_MaxLines = LINES_INI; + pProfile->m_Lines = static_cast<char **>(calloc(pProfile->m_MaxLines, sizeof(char *))); + } + else + { + pProfile->m_MaxLines += LINES_ADD; + pProfile->m_Lines = static_cast<char **>(realloc(pProfile->m_Lines, + pProfile->m_MaxLines * sizeof(char *))); + + memset(&pProfile->m_Lines[pProfile->m_NoLines], + 0, + (pProfile->m_MaxLines - pProfile->m_NoLines - 1) * sizeof(char*)); + } + + if (pProfile->m_Lines == nullptr) + { + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + return nullptr; + } + } + + LineNo = std::min(LineNo, pProfile->m_NoLines); + + if (LineNo < pProfile->m_NoLines) + { + sal_uInt32 i, n; + + memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo], + (pProfile->m_NoLines - LineNo) * sizeof(char *)); + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + osl_TProfileSection* pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line >= LineNo) + pSec->m_Line++; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line >= LineNo) + pSec->m_Entries[n].m_Line++; + } + } + + pProfile->m_NoLines++; + + pProfile->m_Lines[LineNo] = strdup(Line); + + return pProfile->m_Lines[LineNo]; +} + +static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo) +{ + if (LineNo >= pProfile->m_NoLines) + return; + + free(pProfile->m_Lines[LineNo]); + pProfile->m_Lines[LineNo]=nullptr; + if (pProfile->m_NoLines - LineNo > 1) + { + sal_uInt32 i, n; + + memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1], + (pProfile->m_NoLines - LineNo - 1) * sizeof(char *)); + + memset(&pProfile->m_Lines[pProfile->m_NoLines - 1], + 0, + (pProfile->m_MaxLines - pProfile->m_NoLines) * sizeof(char*)); + + /* adjust line references */ + for (i = 0; i < pProfile->m_NoSections; i++) + { + osl_TProfileSection* pSec = &pProfile->m_Sections[i]; + + if (pSec->m_Line > LineNo) + pSec->m_Line--; + + for (n = 0; n < pSec->m_NoEntries; n++) + if (pSec->m_Entries[n].m_Line > LineNo) + pSec->m_Entries[n].m_Line--; + } + } + else + { + pProfile->m_Lines[LineNo] = nullptr; + } + + pProfile->m_NoLines--; +} + +static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection, + sal_uInt32 NoEntry, sal_uInt32 Line, + char* Entry, sal_uInt32 Len) +{ + Entry = stripBlanks(Entry, &Len); + pSection->m_Entries[NoEntry].m_Line = Line; + pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line]; + pSection->m_Entries[NoEntry].m_Len = Len; +} + +static bool addEntry(osl_TProfileImpl* pProfile, + osl_TProfileSection *pSection, + int Line, char* Entry, + sal_uInt32 Len) +{ + if (pSection != nullptr) + { + if (pSection->m_NoEntries >= pSection->m_MaxEntries) + { + if (pSection->m_Entries == nullptr) + { + pSection->m_MaxEntries = ENTRIES_INI; + pSection->m_Entries = static_cast<osl_TProfileEntry *>(malloc( + pSection->m_MaxEntries * sizeof(osl_TProfileEntry))); + } + else + { + pSection->m_MaxEntries += ENTRIES_ADD; + pSection->m_Entries = static_cast<osl_TProfileEntry *>(realloc(pSection->m_Entries, + pSection->m_MaxEntries * sizeof(osl_TProfileEntry))); + } + + if (pSection->m_Entries == nullptr) + { + pSection->m_NoEntries = 0; + pSection->m_MaxEntries = 0; + return false; + } + } + + pSection->m_NoEntries++; + + Entry = stripBlanks(Entry, &Len); + setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line, + Entry, Len); + + return true; + } + + return false; +} + +static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry) +{ + if (NoEntry >= pSection->m_NoEntries) + return; + + if (pSection->m_NoEntries - NoEntry > 1) + { + memmove(&pSection->m_Entries[NoEntry], + &pSection->m_Entries[NoEntry + 1], + (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry)); + pSection->m_Entries[pSection->m_NoEntries - 1].m_Line=0; + pSection->m_Entries[pSection->m_NoEntries - 1].m_Offset=0; + pSection->m_Entries[pSection->m_NoEntries - 1].m_Len=0; + } + + pSection->m_NoEntries--; + +} + +static bool addSection(osl_TProfileImpl* pProfile, int Line, const char* Section, sal_uInt32 Len) +{ + if (pProfile->m_NoSections >= pProfile->m_MaxSections) + { + if (pProfile->m_Sections == nullptr) + { + pProfile->m_MaxSections = SECTIONS_INI; + pProfile->m_Sections = static_cast<osl_TProfileSection *>(calloc(pProfile->m_MaxSections, sizeof(osl_TProfileSection))); + } + else + { + unsigned int idx=0; + unsigned int oldmax=pProfile->m_MaxSections; + + pProfile->m_MaxSections += SECTIONS_ADD; + pProfile->m_Sections = static_cast<osl_TProfileSection *>(realloc(pProfile->m_Sections, + pProfile->m_MaxSections * sizeof(osl_TProfileSection))); + for ( idx = oldmax ; idx < pProfile->m_MaxSections ; ++idx ) + { + pProfile->m_Sections[idx].m_Entries=nullptr; + } + } + + if (pProfile->m_Sections == nullptr) + { + pProfile->m_NoSections = 0; + pProfile->m_MaxSections = 0; + return false; + } + } + + pProfile->m_NoSections++; + + if ( pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries != nullptr ) + { + free(pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries); + } + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = nullptr; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries = 0; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0; + + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line]; + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len; + + return true; +} + +static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection) +{ + sal_uInt32 Section; + + if ((Section = pSection - pProfile->m_Sections) >= pProfile->m_NoSections) + return; + + free (pSection->m_Entries); + pSection->m_Entries=nullptr; + if (pProfile->m_NoSections - Section > 1) + { + memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1], + (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection)); + + memset(&pProfile->m_Sections[pProfile->m_NoSections - 1], + 0, + (pProfile->m_MaxSections - pProfile->m_NoSections) * sizeof(osl_TProfileSection)); + pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = nullptr; + } + else + { + pSection->m_Entries = nullptr; + } + + pProfile->m_NoSections--; +} + +static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, + const char* Section, + const char* Entry, + sal_uInt32 *pNoEntry) +{ + static sal_uInt32 Sect = 0; + sal_uInt32 i, n; + sal_uInt32 Len; + osl_TProfileSection* pSec=nullptr; + + Len = strlen(Section); + + n = Sect; + + for (i = 0; i < pProfile->m_NoSections; i++) + { + n %= pProfile->m_NoSections; + pSec = &pProfile->m_Sections[n]; + if ((Len == pSec->m_Len) && + (strncasecmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len) + == 0)) + break; + n++; + } + + Sect = n; + + if (i < pProfile->m_NoSections) + { + Len = strlen(Entry); + + *pNoEntry = pSec->m_NoEntries; + + for (i = 0; i < pSec->m_NoEntries; i++) + { + const char* pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line] + [pSec->m_Entries[i].m_Offset]; + if ((Len == pSec->m_Entries[i].m_Len) && + (strncasecmp(Entry, pStr, pSec->m_Entries[i].m_Len) + == 0)) + { + *pNoEntry = i; + break; + } + } + } + else + pSec = nullptr; + + return pSec; +} + +static bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile) +{ + sal_uInt32 i; + char* pStr; + char* pChar; + + char* pLine; + + if ( !pFile ) + { + return false; + } + + if ( !pProfile ) + { + return false; + } + + pProfile->m_NoLines = 0; + pProfile->m_NoSections = 0; + + OSL_VERIFY(OslProfile_rewindFile(pFile, false)); + + while ( ( pLine=OslProfile_getLine(pFile) ) != nullptr ) + { + char* bWasAdded = addLine( pProfile, pLine ); + free( pLine ); + SAL_WARN_IF(!bWasAdded, "sal.osl", "addLine( pProfile, pLine ) ==> false"); + if ( ! bWasAdded ) + return false; + } + + for (i = 0; i < pProfile->m_NoLines; i++) + { + pStr = stripBlanks(pProfile->m_Lines[i], nullptr); + + if ((*pStr == '\0') || (*pStr == ';')) + continue; + + if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == nullptr) || + ((pChar - pStr) <= 2)) + { + /* insert entry */ + + if (pProfile->m_NoSections < 1) + continue; + + if ((pChar = strchr(pStr, '=')) == nullptr) + pChar = pStr + strlen(pStr); + + if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1], + i, pStr, pChar - pStr)) + { + SAL_WARN("sal.osl", "Adding entry => false"); + continue; + } + + } + else + { + /* new section */ + + if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1)) + { + SAL_WARN("sal.osl", "Adding section => false"); + continue; + } + + } + } + + return true; +} + +static bool storeProfile(osl_TProfileImpl* pProfile, bool bCleanup) +{ + if (pProfile->m_Lines != nullptr) + { + if (pProfile->m_Flags & FLG_MODIFIED) + { + sal_uInt32 i; + + osl_TFile* pTmpFile = osl_openTmpProfileImpl(pProfile); + + if ( pTmpFile == nullptr ) + { + return false; + } + + OSL_VERIFY(OslProfile_rewindFile(pTmpFile, true)); + + for ( i = 0 ; i < pProfile->m_NoLines ; i++ ) + { + OSL_VERIFY(OslProfile_putLine(pTmpFile, pProfile->m_Lines[i])); + } + + if ( ! writeProfileImpl(pTmpFile) ) + { + if ( pTmpFile->m_pWriteBuf != nullptr ) + { + free(pTmpFile->m_pWriteBuf); + } + + pTmpFile->m_pWriteBuf=nullptr; + pTmpFile->m_nWriteBufLen=0; + pTmpFile->m_nWriteBufFree=0; + + closeFileImpl(pTmpFile,pProfile->m_Flags); + + return false; + } + + pProfile->m_Flags &= ~FLG_MODIFIED; + + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + closeFileImpl(pTmpFile,pProfile->m_Flags); + + osl_ProfileSwapProfileNames(pProfile); + + pProfile->m_pFile = openFileImpl(pProfile->m_FileName,pProfile->m_Flags); + + } + + if (bCleanup) + { + while (pProfile->m_NoLines > 0) + removeLine(pProfile, pProfile->m_NoLines - 1); + + free(pProfile->m_Lines); + pProfile->m_Lines = nullptr; + pProfile->m_NoLines = 0; + pProfile->m_MaxLines = 0; + + while (pProfile->m_NoSections > 0) + removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]); + + free(pProfile->m_Sections); + pProfile->m_Sections = nullptr; + pProfile->m_NoSections = 0; + pProfile->m_MaxSections = 0; + } + } + + return true; +} + +static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl* pProfile) +{ + osl_TFile* pFile=nullptr; + char const * const pszExtension = "tmp"; + char pszTmpName[PATH_MAX]; + oslProfileOption PFlags=0; + + pszTmpName[0] = '\0'; + + /* generate tmp profilename */ + osl_ProfileGenerateExtension(pProfile->m_FileName, pszExtension, pszTmpName, PATH_MAX); + + if ( pszTmpName[0] == 0 ) + { + return nullptr; + } + + if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) ) + { + PFlags |= osl_Profile_WRITELOCK; + } + + /* open this file */ + pFile = openFileImpl(pszTmpName,pProfile->m_Flags | PFlags); + + /* return new pFile */ + return pFile; +} + +static bool osl_ProfileSwapProfileNames(osl_TProfileImpl* pProfile) +{ + char pszBakFile[PATH_MAX]; + char pszTmpFile[PATH_MAX]; + + pszBakFile[0] = '\0'; + pszTmpFile[0] = '\0'; + + osl_ProfileGenerateExtension(pProfile->m_FileName, "bak", pszBakFile, PATH_MAX); + osl_ProfileGenerateExtension(pProfile->m_FileName, "tmp", pszTmpFile, PATH_MAX); + + /* unlink bak */ + unlink( pszBakFile ); + + // Rename ini -> bak, then tmp -> ini: + bool result = rename( pProfile->m_FileName, pszBakFile ) == 0; + if (!result) + { + int e = errno; + SAL_INFO("sal.file", "rename(" << pProfile->m_FileName << "," << pszBakFile << "): " << UnixErrnoString(e)); + } + else + { + SAL_INFO("sal.file", "rename(" << pProfile->m_FileName << "," << pszBakFile << "): OK"); + result = rename( pszTmpFile, pProfile->m_FileName ) == 0; + if (!result) + { + int e = errno; + SAL_INFO("sal.file", "rename(" << pszTmpFile << "," << pProfile->m_FileName << "): " << UnixErrnoString(e)); + } + else + { + SAL_INFO("sal.file", "rename(" << pszTmpFile << "," << pProfile->m_FileName << "): OK"); + } + } + return result; +} + +static void osl_ProfileGenerateExtension(const char* pszFileName, const char* pszExtension, char* pszTmpName, int BufferMaxLen) +{ + char* cursor = pszTmpName; + int len; + + /* concatenate filename + "." + extension, limited to the size of the + * output buffer; in case of overrun, data is truncated at the end... + * and the result is always 0-terminated. + */ + len = strlen(pszFileName); + if(len < BufferMaxLen) + { + memcpy(cursor, pszFileName, len); + cursor += len; + BufferMaxLen -= len; + } + else + { + memcpy(cursor, pszFileName, BufferMaxLen - 1); + cursor += BufferMaxLen - 1; + BufferMaxLen = 1; + } + if(BufferMaxLen > 1) + { + *cursor++ = '.'; + BufferMaxLen -= 1; + } + len = strlen(pszExtension); + if(len < BufferMaxLen) + { + memcpy(cursor, pszExtension, len); + cursor += len; + } + else + { + memcpy(cursor, pszExtension, BufferMaxLen - 1); + cursor += BufferMaxLen - 1; + } + *cursor = 0; +} + +static osl_TProfileImpl* acquireProfile(oslProfile Profile, bool bWriteable) +{ + osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile); + oslProfileOption PFlags=0; + + if ( bWriteable ) + { + PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK; + } + else + { + PFlags = osl_Profile_DEFAULT; + } + + if (pProfile == nullptr) + { + if ( ( pProfile = static_cast<osl_TProfileImpl*>(osl_openProfile(nullptr, PFlags )) ) != nullptr ) + { + pProfile->m_Flags |= FLG_AUTOOPEN; + } + } + else + { + if (! (pProfile->m_Flags & osl_Profile_SYSTEM)) + { + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ))) + { + osl_TStamp Stamp; + + if (! (pProfile->m_pFile = openFileImpl(pProfile->m_FileName, pProfile->m_Flags | PFlags ))) + return nullptr; + + Stamp = OslProfile_getFileStamp(pProfile->m_pFile); + + if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp))) + { + pProfile->m_Stamp = Stamp; + bool bRet = loadProfile(pProfile->m_pFile, pProfile); + SAL_WARN_IF(!bRet, "sal.osl", "loadProfile(pProfile->m_pFile, pProfile) ==> false"); + } + } + else + { + /* A readlock file could not be written */ + if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable) + { + return nullptr; + } + } + } + } + + return pProfile; +} + +static bool releaseProfile(osl_TProfileImpl* pProfile) +{ + if ( pProfile == nullptr ) + { + return false; + } + + if (pProfile->m_Flags & FLG_AUTOOPEN) + { + return osl_closeProfile(static_cast<oslProfile>(pProfile)); + } + + if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ))) + { + if (pProfile->m_Flags & FLG_MODIFIED) + { + bool bRet = storeProfile(pProfile, false); + SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pProfile, false) ==> false"); + } + + closeFileImpl(pProfile->m_pFile,pProfile->m_Flags); + pProfile->m_pFile = nullptr; + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |