252132d975
Change-Id: Icc9cd3410cde2589ea51385c651243e11cc2f1d9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155855 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
1869 lines
52 KiB
C++
1869 lines
52 KiB
C++
/* -*- 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 <sal/log.hxx>
|
|
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#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: */
|