/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright Likewise Software 2004-2008
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Copyright Likewise Software 2004-2008
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
#include "config.h"
#include "ctbase.h"
#include "ctarray.h"
#include
#define GCE(x) GOTO_CLEANUP_ON_CENTERROR((x))
CENTERROR
CTRemoveFile(
PCSTR pszPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
while (1) {
if (unlink(pszPath) < 0) {
if (errno == EINTR) {
continue;
}
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
break;
}
}
error:
return ceError;
}
/*
// TODO: Check access and removability before actual deletion
*/
CENTERROR
CTRemoveDirectory(
PCSTR pszPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
DIR* pDir = NULL;
struct dirent* pDirEntry = NULL;
struct stat statbuf;
CHAR szBuf[PATH_MAX+1];
if ((pDir = opendir(pszPath)) == NULL) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
while ((pDirEntry = readdir(pDir)) != NULL) {
if (!strcmp(pDirEntry->d_name, "..") ||
!strcmp(pDirEntry->d_name, "."))
continue;
sprintf(szBuf, "%s/%s", pszPath, pDirEntry->d_name);
memset(&statbuf, 0, sizeof(struct stat));
if (stat(szBuf, &statbuf) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
ceError = CTRemoveDirectory(szBuf);
BAIL_ON_CENTERIS_ERROR(ceError);
if (rmdir(szBuf) < 0) {
ceError = CTMapSystemError(ceError);
BAIL_ON_CENTERIS_ERROR(ceError);
}
} else {
ceError = CTRemoveFile(szBuf);
BAIL_ON_CENTERIS_ERROR(ceError);
}
}
if(closedir(pDir) < 0)
{
pDir = NULL;
ceError = CTMapSystemError(ceError);
BAIL_ON_CENTERIS_ERROR(ceError);
}
pDir = NULL;
if (rmdir(pszPath) < 0) {
ceError = CTMapSystemError(ceError);
BAIL_ON_CENTERIS_ERROR(ceError);
}
error:
if (pDir)
closedir(pDir);
return ceError;
}
CENTERROR
CTCheckLinkExists(
PCSTR pszPath,
PBOOLEAN pbLinkExists
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
struct stat statbuf;
memset(&statbuf, 0, sizeof(struct stat));
while (1) {
if (lstat(pszPath, &statbuf) < 0) {
if (errno == EINTR)
{
continue;
}
else if (errno == ENOENT || errno == ENOTDIR)
{
*pbLinkExists = FALSE;
break;
}
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
*pbLinkExists = (((statbuf.st_mode & S_IFMT) == S_IFLNK) ? TRUE : FALSE);
break;
}
}
error:
return ceError;
}
CENTERROR
CTCheckSockExists(
PCSTR pszPath,
PBOOLEAN pbSockExists
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
struct stat statbuf;
memset(&statbuf, 0, sizeof(struct stat));
while (1) {
if (stat(pszPath, &statbuf) < 0) {
if (errno == EINTR)
{
continue;
}
else if (errno == ENOENT || errno == ENOTDIR)
{
*pbSockExists = FALSE;
break;
}
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
*pbSockExists = (((statbuf.st_mode & S_IFMT) == S_IFSOCK) ? TRUE : FALSE);
break;
}
}
error:
return ceError;
}
CENTERROR
CTCheckFileExists(
PCSTR pszPath,
PBOOLEAN pbFileExists
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
struct stat statbuf;
memset(&statbuf, 0, sizeof(struct stat));
while (1) {
if (stat(pszPath, &statbuf) < 0) {
if (errno == EINTR)
{
continue;
}
else if (errno == ENOENT || errno == ENOTDIR)
{
*pbFileExists = FALSE;
break;
}
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
*pbFileExists = (((statbuf.st_mode & S_IFMT) == S_IFREG) ? TRUE : FALSE);
break;
}
}
error:
return ceError;
}
CENTERROR
CTCheckDirectoryExists(
PCSTR pszPath,
PBOOLEAN pbDirExists
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
struct stat statbuf;
while (1) {
memset(&statbuf, 0, sizeof(struct stat));
if (stat(pszPath, &statbuf) < 0) {
if (errno == EINTR) {
continue;
}
else if (errno == ENOENT || errno == ENOTDIR) {
*pbDirExists = FALSE;
break;
}
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
/*
The path exists. Is it a directory?
*/
*pbDirExists = (((statbuf.st_mode & S_IFMT) == S_IFDIR) ? TRUE : FALSE);
break;
}
error:
return ceError;
}
CENTERROR
CTMoveFile(
PCSTR pszSrcPath,
PCSTR pszDstPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
if (rename(pszSrcPath, pszDstPath) < 0) {
ceError = CTMapSystemError(errno);
}
return ceError;
}
CENTERROR
CTCopyFileWithPerms(
PCSTR pszSrcPath,
PCSTR pszDstPath,
mode_t dwPerms
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCSTR pszTmpSuffix = ".tmp_likewise";
PSTR pszTmpPath = NULL;
BOOLEAN bRemoveFile = FALSE;
CHAR szBuf[1024+1];
int iFd = -1;
int oFd = -1;
DWORD dwBytesRead = 0;
if (IsNullOrEmptyString(pszSrcPath) ||
IsNullOrEmptyString(pszDstPath)) {
ceError = CENTERROR_INVALID_PARAMETER;
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTAllocateMemory(strlen(pszDstPath)+strlen(pszTmpSuffix)+2,
(PVOID*)&pszTmpPath);
BAIL_ON_CENTERIS_ERROR(ceError);
strcpy(pszTmpPath, pszDstPath);
strcat(pszTmpPath, pszTmpSuffix);
if ((iFd = open(pszSrcPath, O_RDONLY, S_IRUSR)) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if ((oFd = open(pszTmpPath, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
bRemoveFile = TRUE;
while (1) {
if ((dwBytesRead = read(iFd, szBuf, 1024)) < 0) {
if (errno == EINTR)
continue;
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (dwBytesRead == 0)
break;
if (write(oFd, szBuf, dwBytesRead) != dwBytesRead) {
if (errno == EINTR)
continue;
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
}
close(iFd); iFd = -1;
close(oFd); oFd = -1;
ceError = CTMoveFile(pszTmpPath, pszDstPath);
BAIL_ON_CENTERIS_ERROR(ceError);
bRemoveFile = FALSE;
ceError = CTChangePermissions(pszDstPath, dwPerms);
BAIL_ON_CENTERIS_ERROR(ceError);
error:
if (iFd >= 0)
close(iFd);
if (oFd >= 0)
close(oFd);
if (bRemoveFile) {
CTRemoveFile(pszTmpPath);
}
if (pszTmpPath)
CTFreeString(pszTmpPath);
return ceError;
}
CENTERROR
CTGetOwnerAndPermissions(
PCSTR pszSrcPath,
uid_t * uid,
gid_t * gid,
mode_t * mode
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
struct stat statbuf;
memset(&statbuf, 0, sizeof(struct stat));
if (stat(pszSrcPath, &statbuf) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
*uid = statbuf.st_uid;
*gid = statbuf.st_gid;
*mode = statbuf.st_mode;
error:
return ceError;
}
CENTERROR
CTGetOwnerUID(
PCSTR pszFilePath,
uid_t* pUid
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
struct stat statbuf;
memset(&statbuf, 0, sizeof(struct stat));
if (stat(pszFilePath, &statbuf) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
*pUid = statbuf.st_uid;
error:
return ceError;
}
CENTERROR
CTCheckFileOrLinkExists(
PCSTR pszPath,
PBOOLEAN pbExists
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
BAIL_ON_CENTERIS_ERROR(ceError = CTCheckFileExists(pszPath, pbExists));
if(*pbExists == TRUE)
goto error;
BAIL_ON_CENTERIS_ERROR(ceError = CTCheckLinkExists(pszPath, pbExists));
error:
return ceError;
}
CENTERROR
CTGetFileTimeStamps(
PCSTR pszFilePath,
time_t *patime, /* time of last access */
time_t *pmtime, /* time of last modification */
time_t *pctime ) /* time of last status change */
{
CENTERROR ceError = CENTERROR_SUCCESS;
struct stat statbuf;
memset(&statbuf, 0, sizeof(struct stat));
if (stat(pszFilePath, &statbuf) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if ( patime ) {
*patime = statbuf.st_atime;
}
if ( pmtime ) {
*pmtime = statbuf.st_mtime;
}
if ( pctime ) {
*pctime = statbuf.st_ctime;
}
error:
return ceError;
}
CENTERROR
CTCopyFileWithOriginalPerms(
PCSTR pszSrcPath,
PCSTR pszDstPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
uid_t uid;
gid_t gid;
mode_t mode;
ceError = CTGetOwnerAndPermissions(pszSrcPath, &uid, &gid, &mode);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTCopyFileWithPerms(pszSrcPath, pszDstPath, mode);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTChangeOwnerAndPermissions(pszDstPath, uid, gid, mode);
BAIL_ON_CENTERIS_ERROR(ceError);
error:
return ceError;
}
CENTERROR
CTChangePermissions(
PCSTR pszPath,
mode_t dwFileMode
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
while (1) {
if (chmod(pszPath, dwFileMode) < 0) {
if (errno == EINTR) {
continue;
}
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
break;
}
}
error:
return ceError;
}
CENTERROR
CTChangeOwner(
PCSTR pszPath,
uid_t uid,
gid_t gid
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
while (1) {
if (chown(pszPath, uid, gid) < 0) {
if (errno == EINTR) {
continue;
}
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
break;
}
}
error:
return ceError;
}
CENTERROR
CTChangeOwnerAndPermissions(
PCSTR pszPath,
uid_t uid,
gid_t gid,
mode_t dwFileMode
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
ceError = CTChangeOwner(pszPath, uid, gid);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTChangePermissions(pszPath, dwFileMode);
BAIL_ON_CENTERIS_ERROR(ceError);
error:
return ceError;
}
CENTERROR
CTGetCurrentDirectoryPath(
PSTR* ppszPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
CHAR szBuf[PATH_MAX+1];
PSTR pszPath = NULL;
if (getcwd(szBuf, PATH_MAX) == NULL) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTAllocateString(szBuf, &pszPath);
BAIL_ON_CENTERIS_ERROR(ceError);
*ppszPath = pszPath;
return ceError;
error:
if (pszPath) {
CTFreeString(pszPath);
}
return ceError;
}
CENTERROR
CTChangeDirectory(
PSTR pszPath
)
{
if (pszPath == NULL || *pszPath == '\0')
return CENTERROR_INVALID_PARAMETER;
if (chdir(pszPath) < 0)
return CTMapSystemError(errno);
return CENTERROR_SUCCESS;
}
CENTERROR
CTCreateTempDirectory(
PSTR *pszPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PSTR tmpDir;
PSTR template = NULL;
if (pszPath == NULL)
{
BAIL_ON_CENTERIS_ERROR(ceError = CENTERROR_INVALID_PARAMETER);
}
*pszPath = NULL;
tmpDir = getenv("TMPDIR");
if(tmpDir == NULL)
tmpDir = "/tmp";
ceError = CTAllocateStringPrintf(&template, "%s/likewisetmpXXXXXX", tmpDir);
BAIL_ON_CENTERIS_ERROR(ceError);
if (mkdtemp(template) == NULL) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
*pszPath = template;
template = NULL;
error:
CT_SAFE_FREE_STRING(template);
return ceError;
}
static CENTERROR
CTCreateDirectoryInternal(
PSTR pszPath,
PSTR pszLastSlash,
mode_t dwFileMode
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PSTR pszSlash = NULL;
BOOLEAN bDirExists = FALSE;
BOOLEAN bDirCreated = FALSE;
pszSlash = pszLastSlash ? strchr(pszLastSlash + 1, '/') : strchr(pszPath, '/');
if (pszSlash)
{
*pszSlash = '\0';
}
if (pszPath[0])
{
ceError = CTCheckDirectoryExists(pszPath, &bDirExists);
BAIL_ON_CENTERIS_ERROR(ceError);
if (!bDirExists)
{
if (mkdir(pszPath, S_IRWXU) != 0)
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
bDirCreated = TRUE;
}
}
if (pszSlash)
{
*pszSlash = '/';
}
if (pszSlash)
{
ceError = CTCreateDirectoryInternal(pszPath, pszSlash, dwFileMode);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (pszSlash)
{
*pszSlash = '\0';
}
if (bDirCreated)
{
ceError = CTChangePermissions(pszPath, dwFileMode);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (pszSlash)
{
*pszSlash = '/';
}
cleanup:
return ceError;
error:
if (pszSlash)
{
*pszSlash = '\0';
}
if (bDirCreated)
{
CTRemoveDirectory(pszPath);
}
if (pszSlash)
{
*pszSlash = '/';
}
goto cleanup;
}
CENTERROR
CTCreateDirectory(
PCSTR pszPath,
mode_t dwFileMode
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PSTR pszTmpPath = NULL;
if (pszPath == NULL)
{
ceError = CENTERROR_INVALID_PARAMETER;
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTAllocateString(pszPath, &pszTmpPath);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTCreateDirectoryInternal(pszTmpPath, NULL, dwFileMode);
BAIL_ON_CENTERIS_ERROR(ceError);
cleanup:
CT_SAFE_FREE_STRING(pszTmpPath);
return ceError;
error:
goto cleanup;
}
static
CENTERROR
CTGetMatchingDirEntryPathsInFolder(PCSTR pszDirPath,
PCSTR pszFileNameRegExp,
PSTR** pppszHostFilePaths,
PDWORD pdwNPaths,
DWORD dirEntryType)
{
typedef struct __PATHNODE
{
PSTR pszPath;
struct __PATHNODE *pNext;
} PATHNODE, *PPATHNODE;
CENTERROR ceError = CENTERROR_SUCCESS;
DIR* pDir = NULL;
struct dirent* pDirEntry = NULL;
regex_t rx;
BOOLEAN rxAllocated = FALSE;
regmatch_t* pResult = NULL;
size_t nMatch = 1;
DWORD dwNPaths = 0;
DWORD iPath = 0;
PSTR* ppszHostFilePaths = NULL;
CHAR szBuf[PATH_MAX+1];
struct stat statbuf;
PPATHNODE pPathList = NULL;
PPATHNODE pPathNode = NULL;
BOOLEAN isDirPathDir;
*pppszHostFilePaths = NULL;
*pdwNPaths = 0;
ceError = CTCheckDirectoryExists(pszDirPath, &isDirPathDir);
BAIL_ON_CENTERIS_ERROR(ceError);
if(!isDirPathDir)
BAIL_ON_CENTERIS_ERROR(ceError = CENTERROR_INVALID_DIRECTORY);
if (regcomp(&rx, pszFileNameRegExp, REG_EXTENDED) != 0) {
ceError = CENTERROR_REGEX_COMPILE_FAILED;
BAIL_ON_CENTERIS_ERROR(ceError);
}
rxAllocated = TRUE;
ceError = CTAllocateMemory(sizeof(regmatch_t), (PVOID*)&pResult);
BAIL_ON_CENTERIS_ERROR(ceError);
pDir = opendir(pszDirPath);
if (pDir == NULL) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
while ((pDirEntry = readdir(pDir)) != NULL) {
int copied = snprintf(szBuf, sizeof(szBuf), "%s/%s", pszDirPath, pDirEntry->d_name);
if (copied >= sizeof(szBuf))
{
//Skip pathnames that are too long
continue;
}
memset(&statbuf, 0, sizeof(struct stat));
if (stat(szBuf, &statbuf) < 0) {
if(errno == ENOENT)
{
//This occurs when there is a symbolic link pointing to a
//location that doesn't exist, because stat looks at the final
//file, not the link. Since this file doesn't exist anyway,
//just skip it.
continue;
}
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
/*
* For now, we are searching only for regular files
* This may be enhanced in the future to support additional
* file system entry types
*/
if (((statbuf.st_mode & S_IFMT) == dirEntryType) &&
(regexec(&rx, pDirEntry->d_name, nMatch, pResult, 0) == 0)) {
dwNPaths++;
ceError = CTAllocateMemory(sizeof(PATHNODE), (PVOID*)&pPathNode);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTAllocateString(szBuf, &pPathNode->pszPath);
BAIL_ON_CENTERIS_ERROR(ceError);
pPathNode->pNext = pPathList;
pPathList = pPathNode;
pPathNode = NULL;
}
}
if (pPathList) {
ceError = CTAllocateMemory(sizeof(PSTR)*dwNPaths,
(PVOID*)&ppszHostFilePaths);
BAIL_ON_CENTERIS_ERROR(ceError);
/*
* The linked list is in reverse.
* Assign values in reverse to get it right
*/
iPath = dwNPaths-1;
pPathNode = pPathList;
while (pPathNode) {
*(ppszHostFilePaths+iPath) = pPathNode->pszPath;
pPathNode->pszPath = NULL;
pPathNode = pPathNode->pNext;
iPath--;
}
}
*pppszHostFilePaths = ppszHostFilePaths;
ppszHostFilePaths = NULL;
*pdwNPaths = dwNPaths;
error:
if (ppszHostFilePaths) {
CTFreeStringArray(ppszHostFilePaths, dwNPaths);
}
if (pPathNode) {
pPathNode->pNext = pPathList;
pPathList = pPathNode;
}
while(pPathList) {
pPathNode = pPathList;
pPathList = pPathList->pNext;
if (pPathNode->pszPath)
CTFreeString(pPathNode->pszPath);
CTFreeMemory(pPathNode);
}
if(rxAllocated)
regfree(&rx);
if (pResult) {
CTFreeMemory(pResult);
}
if (pDir)
closedir(pDir);
return ceError;
}
CENTERROR
CTGetMatchingFilePathsInFolder(PCSTR pszDirPath,
PCSTR pszFileNameRegExp,
PSTR** pppszHostFilePaths,
PDWORD pdwNPaths)
{
return CTGetMatchingDirEntryPathsInFolder(pszDirPath,
pszFileNameRegExp,
pppszHostFilePaths,
pdwNPaths,
S_IFREG);
}
CENTERROR
CTGetMatchingDirPathsInFolder(PCSTR pszDirPath,
PCSTR pszDirNameRegExp,
PSTR** pppszHostDirPaths,
PDWORD pdwNPaths)
{
return CTGetMatchingDirEntryPathsInFolder(pszDirPath,
pszDirNameRegExp,
pppszHostDirPaths,
pdwNPaths,
S_IFDIR);
}
CENTERROR
CTCheckFileHoldsPattern(
PCSTR pszFilePath,
PCSTR pszPattern,
PBOOLEAN pbPatternExists
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
FILE* fp = NULL;
CHAR szBuf[1024+1];
regex_t rx;
regmatch_t* pResult = NULL;
size_t nMatch = 1;
BOOLEAN bPatternExists = FALSE;
memset(&rx, 0, sizeof(regex_t));
if (regcomp(&rx, pszPattern, REG_EXTENDED) != 0) {
ceError = CENTERROR_REGEX_COMPILE_FAILED;
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTAllocateMemory(sizeof(regmatch_t), (PVOID*)&pResult);
BAIL_ON_CENTERIS_ERROR(ceError);
fp = fopen(pszFilePath, "r");
if (fp == NULL) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
while (!feof(fp)) {
if (fgets(szBuf, 1024, fp)) {
if (regexec(&rx, szBuf, nMatch, pResult, 0) == 0) {
bPatternExists = TRUE;
break;
}
} else if (!feof(fp)) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
}
*pbPatternExists = bPatternExists;
error:
regfree(&rx);
if (pResult)
CTFreeMemory(pResult);
if (fp != NULL)
fclose(fp);
return ceError;
}
CENTERROR
CTGetAbsolutePath(
PSTR pszRelativePath,
PSTR* ppszAbsolutePath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
CHAR szBuf[PATH_MAX+1];
if (realpath(pszRelativePath, szBuf) == NULL) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTAllocateString(szBuf, ppszAbsolutePath);
BAIL_ON_CENTERIS_ERROR(ceError);
error:
return ceError;
}
CENTERROR
CTRemoveFiles(
PSTR pszPath,
BOOLEAN fDirectory,
BOOLEAN fRecursive
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
CHAR szCommand[2 * PATH_MAX + 1];
sprintf(szCommand, "/bin/rm -f %s %s %s",
fDirectory ? "-d" : "",
fRecursive ? "-r" : "",
pszPath);
if (system(szCommand) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
error:
return(ceError);
}
CENTERROR
CTGetSymLinkTarget(
PCSTR pszPath,
PSTR* ppszTargetPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
CHAR szBuf[PATH_MAX+1];
memset(szBuf, 0, PATH_MAX);
while (1) {
if (readlink(pszPath, szBuf, PATH_MAX) < 0) {
if (errno == EINTR)
continue;
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
break;
}
ceError = CTAllocateString(szBuf, ppszTargetPath);
BAIL_ON_CENTERIS_ERROR(ceError);
error:
return ceError;
}
CENTERROR
CTCreateSymLink(
PCSTR pszOldPath,
PCSTR pszNewPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
if (IsNullOrEmptyString(pszOldPath) ||
IsNullOrEmptyString(pszNewPath)) {
ceError = CENTERROR_INVALID_PARAMETER;
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (symlink(pszOldPath, pszNewPath) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
error:
return ceError;
}
CENTERROR
CTBackupFile(
PCSTR path
)
{
CENTERROR ceError;
PSTR backupPath = NULL;
BOOLEAN exists;
ceError = CTCheckFileExists(path, &exists);
CLEANUP_ON_CENTERROR(ceError);
if (!exists)
{
/* Do not need to backup, since the file does not yet exist. */
goto cleanup;
}
ceError = CTAllocateStringPrintf(&backupPath, "%s.lwidentity.orig", path);
CLEANUP_ON_CENTERROR(ceError);
ceError = CTCheckFileExists(backupPath, &exists);
CLEANUP_ON_CENTERROR(ceError);
if (exists)
{
CTFreeMemory(backupPath);
backupPath = NULL;
ceError = CTAllocateStringPrintf(&backupPath, "%s.lwidentity.bak", path);
CLEANUP_ON_CENTERROR(ceError);
}
ceError = CTCopyFileWithOriginalPerms(path, backupPath);
CLEANUP_ON_CENTERROR(ceError);
cleanup:
if (backupPath)
{
CTFreeMemory(backupPath);
backupPath = NULL;
}
return ceError;
}
/*
// On some unix systems, you may not be allowed to
// move files across devices. So, we copy the file to a
// tmp file and then move it to the target location -
// and remove the original file
*/
CENTERROR
CTMoveFileAcrossDevices(
PCSTR pszSrcPath,
PCSTR pszDstPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
CHAR szTmpPath[PATH_MAX+1] = "";
BOOLEAN bRemoveFile = FALSE;
uid_t uid;
gid_t gid;
mode_t mode;
sprintf(szTmpPath, "%s_lwi_.tmp", pszDstPath);
ceError = CTGetOwnerAndPermissions(pszSrcPath, &uid, &gid, &mode);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTCopyFileWithPerms(pszSrcPath, szTmpPath, mode);
BAIL_ON_CENTERIS_ERROR(ceError);
bRemoveFile = TRUE;
ceError = CTMoveFile(szTmpPath, pszDstPath);
BAIL_ON_CENTERIS_ERROR(ceError);
bRemoveFile = FALSE;
ceError = CTRemoveFile(pszSrcPath);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTChangeOwnerAndPermissions(pszDstPath, uid, gid, mode);
BAIL_ON_CENTERIS_ERROR(ceError);
error:
if (bRemoveFile && !IsNullOrEmptyString(szTmpPath))
CTRemoveFile(szTmpPath);
return ceError;
}
/*
// Do not use this function on very large files since it reads the
// entire file into memory.
*/
CENTERROR
CTReadFile(
PCSTR pszFilePath,
PSTR *ppBuffer,
PLONG pSize )
{
CENTERROR ceError = CENTERROR_SUCCESS;
struct stat statbuf;
FILE *fp = NULL;
*ppBuffer = NULL;
if(pSize != NULL)
*pSize = 0;
memset(&statbuf, 0, sizeof(struct stat));
if (stat(pszFilePath, &statbuf) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (statbuf.st_size > 0) {
/* allocate one additional byte of memory and set it to NULL to
allow for functions like strtok() to work properly */
ceError = CTAllocateMemory(statbuf.st_size + 1, (VOID*)ppBuffer);
BAIL_ON_CENTERIS_ERROR(ceError);
fp = fopen( pszFilePath, "r" );
if ( fp == NULL ){
ceError = CENTERROR_GP_FILE_OPEN_FAILED;
BAIL_ON_CENTERIS_ERROR(ceError);
}
if ( fread( *ppBuffer, statbuf.st_size, 1, fp ) != 1 ) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
fclose(fp);
fp = NULL;
if(pSize != NULL)
*pSize = statbuf.st_size;
}
return ceError;
error:
if (*ppBuffer) {
CTFreeMemory( *ppBuffer );
*ppBuffer = NULL;
}
if (fp) {
fclose( fp );
}
return ceError;
}
CENTERROR
CTOpenFile(
PCSTR path,
PCSTR mode,
FILE** handle)
{
CENTERROR ceError = CENTERROR_SUCCESS;
*handle = fopen(path, mode);
if (!*handle)
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
error:
return ceError;
}
CENTERROR
CTFileStreamWrite(
FILE* handle,
PCSTR data,
unsigned int size)
{
CENTERROR ceError = CENTERROR_SUCCESS;
unsigned int written = 0;
while (written < size)
{
int amount = fwrite(data+written, 1, size-written, handle);
if (amount < 0)
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
written += amount;
}
error:
return ceError;
}
CENTERROR
CTFilePrintf(
FILE* handle,
PCSTR format,
...
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
va_list args;
int count;
va_start(args, format);
count = vfprintf(handle, format, args);
va_end(args);
if (count < 0)
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
error:
return ceError;
}
CENTERROR
CTCloseFile(
FILE* handle
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
if (fclose(handle))
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
error:
return ceError;
}
CENTERROR
CTSafeCloseFile(
FILE** handle
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
if(*handle == NULL)
goto cleanup;
if (fclose(*handle))
{
ceError = CTMapSystemError(errno);
GCE(ceError);
}
cleanup:
*handle = NULL;
return ceError;
}
CENTERROR
CTFileContentsSame(
PCSTR pszFilePath1,
PCSTR pszFilePath2,
PBOOLEAN pbSame
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
FILE* fp1 = NULL;
FILE* fp2 = NULL;
BOOLEAN f1IsFile, f1IsLink;
BOOLEAN f2IsFile, f2IsLink;
ceError = CTCheckFileExists(pszFilePath1, &f1IsFile);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTCheckLinkExists(pszFilePath1, &f1IsLink);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTCheckFileExists(pszFilePath2, &f2IsFile);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTCheckLinkExists(pszFilePath2, &f2IsLink);
BAIL_ON_CENTERIS_ERROR(ceError);
f1IsFile |= f1IsLink;
f2IsFile |= f2IsLink;
if(!f1IsFile && !f2IsFile)
{
*pbSame = TRUE;
goto error;
}
if(!f1IsFile || !f2IsFile)
{
*pbSame = FALSE;
goto error;
}
ceError = CTOpenFile(pszFilePath1, "r", &fp1);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTOpenFile(pszFilePath2, "r", &fp2);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTStreamContentsSame(fp1, fp2, pbSame);
BAIL_ON_CENTERIS_ERROR(ceError);
error:
if (fp1 != NULL)
fclose(fp1);
if (fp2 != NULL)
fclose(fp2);
return ceError;
}
CENTERROR
CTStreamContentsSame(
FILE *fp1,
FILE *fp2,
PBOOLEAN pbSame
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
unsigned char buffer1[1024], buffer2[1024];
size_t read1, read2;
while (1) {
read1 = fread(buffer1, 1, sizeof(buffer1), fp1);
if(read1 < sizeof(buffer1) && ferror(fp1))
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
read2 = fread(buffer2, 1, sizeof(buffer2), fp2);
if(read2 < sizeof(buffer2) && ferror(fp2))
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if(read1 != read2 || memcmp(buffer1, buffer2, read1) != 0)
{
*pbSame = FALSE;
goto error;
}
if(read1 == 0)
break;
}
*pbSame = TRUE;
error:
return ceError;
}
CENTERROR
CTFindSed(
PSTR *sedPath
)
{
CENTERROR ceError = CTFindFileInPath("sed", "/bin:/usr/bin", sedPath);
if(ceError == CENTERROR_FILE_NOT_FOUND)
ceError = CENTERROR_SED_NOT_FOUND;
return ceError;
}
CENTERROR
CTWillSedChangeFile(
PCSTR pszSrcPath,
PCSTR pszExpression,
BOOLEAN *changes
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCSTR ppszArgs[] =
{ NULL,
NULL,
NULL,
NULL,
};
FILE *srcFile = NULL;
FILE *sedOut = NULL;
int duppedFdout = -1;
int argPos = 0;
PPROCINFO pProcInfo = NULL;
LONG status = 0;
PSTR sedPath = NULL;
BOOLEAN same = FALSE;
BAIL_ON_CENTERIS_ERROR(ceError = CTFindSed(&sedPath));
ppszArgs[argPos++] = sedPath;
ppszArgs[argPos++] = pszExpression;
ceError = CTOpenFile(pszSrcPath, "r", &srcFile);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTSpawnProcessWithFds(ppszArgs[0], (const PSTR *)ppszArgs, fileno(srcFile), -1, 2, &pProcInfo);
BAIL_ON_CENTERIS_ERROR(ceError);
/* Get a FILE * for the stdout file descriptor */
duppedFdout = dup(pProcInfo->fdout);
if (duppedFdout < 0)
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
sedOut = fdopen(duppedFdout, "r");
if(sedOut == NULL)
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
duppedFdout = -1;
// Reopen the source file so that we don't share the file offset with
// sed (and thus we can reread the same data).
ceError = CTCloseFile(srcFile);
srcFile = NULL;
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTOpenFile(pszSrcPath, "r", &srcFile);
BAIL_ON_CENTERIS_ERROR(ceError);
BAIL_ON_CENTERIS_ERROR(ceError = CTStreamContentsSame(srcFile, sedOut, &same));
ceError = CTGetExitStatus(pProcInfo, &status);
BAIL_ON_CENTERIS_ERROR(ceError);
if (status != 0) {
BAIL_ON_CENTERIS_ERROR(ceError = CENTERROR_COMMAND_FAILED);
}
ceError = CTCloseFile(srcFile);
srcFile = NULL;
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTCloseFile(sedOut);
sedOut = NULL;
BAIL_ON_CENTERIS_ERROR(ceError);
*changes = !same;
error:
if(srcFile != NULL)
CTCloseFile(srcFile);
if(sedOut != NULL)
CTCloseFile(sedOut);
if(duppedFdout != -1)
close(duppedFdout);
if (pProcInfo)
CTFreeProcInfo(pProcInfo);
CT_SAFE_FREE_STRING(sedPath);
return ceError;
}
CENTERROR
CTRunSedOnFile(
PCSTR pszSrcPath,
PCSTR pszDstPath,
BOOLEAN bDashN,
PCSTR pszExpression
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCSTR ppszArgs[] =
{ NULL,
NULL,
NULL,
NULL,
};
int dwFdIn = -1, dwFdOut = -1;
int argPos = 0;
PPROCINFO pProcInfo = NULL;
LONG status = 0;
PSTR tempPath = NULL;
uid_t uid;
gid_t gid;
mode_t mode;
PSTR sedPath = NULL;
BOOLEAN isSame;
PSTR pszFinalPath = NULL;
BAIL_ON_CENTERIS_ERROR(ceError = CTFindSed(&sedPath));
ppszArgs[argPos++] = sedPath;
if(bDashN)
ppszArgs[argPos++] = "-n";
ppszArgs[argPos++] = pszExpression;
ceError = CTGetFileTempPath(
pszDstPath,
&pszFinalPath,
&tempPath);
BAIL_ON_CENTERIS_ERROR(ceError);
dwFdIn = open(pszSrcPath, O_RDONLY);
if (dwFdIn < 0)
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
dwFdOut = open(tempPath, O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
if (dwFdOut < 0)
{
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
BAIL_ON_CENTERIS_ERROR(ceError = CTGetOwnerAndPermissions(pszSrcPath, &uid, &gid, &mode));
BAIL_ON_CENTERIS_ERROR(ceError = CTChangeOwnerAndPermissions(tempPath, uid, gid, mode));
ceError = CTSpawnProcessWithFds(ppszArgs[0], (const PSTR *)ppszArgs, dwFdIn, dwFdOut, 2, &pProcInfo);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTGetExitStatus(pProcInfo, &status);
BAIL_ON_CENTERIS_ERROR(ceError);
if (status != 0) {
BAIL_ON_CENTERIS_ERROR(ceError = CENTERROR_COMMAND_FAILED);
}
BAIL_ON_CENTERIS_ERROR(ceError = CTFileContentsSame(tempPath, pszFinalPath, &isSame));
if (isSame)
{
BAIL_ON_CENTERIS_ERROR(ceError = CTRemoveFile(tempPath));
}
else
{
ceError = CTSafeReplaceFile(pszFinalPath, tempPath);
BAIL_ON_CENTERIS_ERROR(ceError);
}
error:
if(dwFdIn != -1)
close(dwFdIn);
if(dwFdOut != -1)
{
close(dwFdOut);
if(!CENTERROR_IS_OK(ceError))
{
CTRemoveFile(tempPath);
}
}
if (pProcInfo)
CTFreeProcInfo(pProcInfo);
CT_SAFE_FREE_STRING(tempPath);
CT_SAFE_FREE_STRING(pszFinalPath);
CT_SAFE_FREE_STRING(sedPath);
return ceError;
}
CENTERROR
CTCloneFilePerms(
PCSTR pszTemplatePath,
PCSTR pszDstPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
uid_t uid;
gid_t gid;
mode_t mode;
ceError = CTGetOwnerAndPermissions(pszTemplatePath, &uid, &gid, &mode);
CLEANUP_ON_CENTERROR(ceError);
ceError = CTChangeOwnerAndPermissions(pszDstPath, uid, gid, mode);
CLEANUP_ON_CENTERROR(ceError);
cleanup:
return ceError;
}
CENTERROR
CTFindFileInPath(
PCSTR filename,
PCSTR searchPath,
PSTR* foundPath
)
{
return CTFindInPath(NULL, filename, searchPath, foundPath);
}
CENTERROR
CTFindInPath(
PCSTR rootPrefix,
PCSTR filename,
PCSTR searchPath,
PSTR* foundPath
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
//Copy the search path so that strtok can be run on it
PSTR mySearchPath = NULL;
PSTR strtokSavePtr = NULL;
PSTR currentDir = NULL;
PSTR testPath = NULL;
BOOLEAN exists = FALSE;
if(foundPath != NULL)
*foundPath = NULL;
if(rootPrefix == NULL)
rootPrefix = "";
GCE(ceError = CTStrdup(searchPath, &mySearchPath));
currentDir = strtok_r(mySearchPath, ":", &strtokSavePtr);
while(TRUE)
{
CT_SAFE_FREE_STRING(testPath);
GCE(ceError = CTAllocateStringPrintf(&testPath, "%s%s/%s", rootPrefix, currentDir, filename));
GCE(ceError = CTCheckFileOrLinkExists(testPath, &exists));
if(exists)
{
if(foundPath != NULL)
{
GCE(ceError = CTAllocateStringPrintf(foundPath, "%s/%s", currentDir, filename));
}
break;
}
currentDir = strtok_r(NULL, ":", &strtokSavePtr);
if(currentDir == NULL)
{
GCE(ceError = CENTERROR_FILE_NOT_FOUND);
}
}
cleanup:
CT_SAFE_FREE_STRING(mySearchPath);
CT_SAFE_FREE_STRING(testPath);
return ceError;
}
CENTERROR
CTGetFileDiff(
PCSTR first,
PCSTR second,
PSTR *diff,
BOOLEAN failIfNoDiff
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PSTR diffPath = NULL;
PCSTR args[4] = { NULL, first, second, NULL };
int exitCode;
*diff = NULL;
ceError = CTFindFileInPath("diff",
"/bin:/usr/bin:/sbin:/usr/sbin", &diffPath);
if(ceError == CENTERROR_FILE_NOT_FOUND && !failIfNoDiff)
{
GCE(ceError = CTStrdup("Diff command not found", diff));
goto cleanup;
}
GCE(ceError);
args[0] = diffPath;
GCE(ceError = CTCaptureOutputWithStderrEx(args[0], args, FALSE, diff,
&exitCode));
//Diff returns 1 when the files are different
if(exitCode == 1)
{
exitCode = 0;
}
if(exitCode != 0)
GCE(ceError = CENTERROR_COMMAND_FAILED);
cleanup:
CT_SAFE_FREE_STRING(diffPath);
return ceError;
}
CENTERROR
CTGetFileTempPath(
PCSTR unresolvedSrcPath,
PSTR* resolvedSrcPath,
PSTR* tempPath)
{
PSTR symTarget = NULL;
PSTR newPath = NULL;
PSTR currentPath = NULL;
CENTERROR ceError = CENTERROR_SUCCESS;
// do not free
PSTR separator = NULL;
if (resolvedSrcPath)
{
*resolvedSrcPath = NULL;
}
if (tempPath)
{
*tempPath = NULL;
}
ceError = CTAllocateString(unresolvedSrcPath, ¤tPath);
GCE(ceError);
while (1)
{
ceError = CTGetSymLinkTarget(
currentPath,
&symTarget);
if (ceError == CTMapSystemError(EINVAL))
{
// The last symlink component was resolved
ceError = 0;
break;
}
else if (ceError == CTMapSystemError(ENOENT))
{
// The target does not exist yet. The caller should create this path
ceError = 0;
break;
}
GCE(ceError);
// Strip off the file component
separator = strrchr(currentPath, '/');
if (separator != NULL)
{
separator[1] = 0;
}
if (symTarget[0] == '/')
{
GCE(ceError = CTAllocateStringPrintf(&newPath, "%s", symTarget));
}
else
{
GCE(ceError = CTAllocateStringPrintf(&newPath, "%s%s", currentPath,
symTarget));
}
CT_SAFE_FREE_STRING(currentPath);
CT_SAFE_FREE_STRING(symTarget);
currentPath = newPath;
newPath = NULL;
}
if (tempPath)
{
GCE(ceError = CTAllocateStringPrintf(tempPath, "%s.lwidentity.new", currentPath));
}
if (resolvedSrcPath)
{
*resolvedSrcPath = currentPath;
currentPath = NULL;
}
cleanup:
CT_SAFE_FREE_STRING(currentPath);
CT_SAFE_FREE_STRING(newPath);
CT_SAFE_FREE_STRING(symTarget);
return ceError;
}
CENTERROR
CTSafeReplaceFile(
PCSTR finalName,
PCSTR replaceWith)
{
CENTERROR ceError = CENTERROR_SUCCESS;
GCE(ceError = CTCloneFilePerms(finalName, replaceWith));
GCE(ceError = CTBackupFile(finalName));
GCE(ceError = CTMoveFile(replaceWith, finalName));
cleanup:
return ceError;
}
CENTERROR
CTCopyDirectory(
PCSTR source,
PCSTR dest
)
{
uid_t uid;
gid_t gid;
mode_t mode;
CENTERROR ceError = CENTERROR_SUCCESS;
DIR* pDir = NULL;
struct dirent* pDirEntry = NULL;
struct stat statbuf;
PSTR srcPath = NULL;
PSTR destPath = NULL;
GCE(ceError = CTGetOwnerAndPermissions(source, &uid, &gid, &mode));
GCE(ceError = CTCreateDirectory(dest, mode));
GCE(ceError = CTChangeOwnerAndPermissions(dest, uid, gid, mode));
if ((pDir = opendir(source)) == NULL) {
GCE(ceError = CTMapSystemError(errno));
}
while ((pDirEntry = readdir(pDir)) != NULL) {
if (!strcmp(pDirEntry->d_name, "..") ||
!strcmp(pDirEntry->d_name, "."))
continue;
GCE(ceError = CTAllocateStringPrintf(&srcPath, "%s/%s", source,
pDirEntry->d_name));
GCE(ceError = CTAllocateStringPrintf(&destPath, "%s/%s", dest,
pDirEntry->d_name));
memset(&statbuf, 0, sizeof(struct stat));
if (stat(srcPath, &statbuf) < 0) {
GCE(ceError = CTMapSystemError(errno));
}
if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
GCE(ceError = CTCopyDirectory(srcPath, destPath));
} else {
GCE(ceError = CTCopyFileWithOriginalPerms(srcPath, destPath));
}
}
if(closedir(pDir) < 0)
{
pDir = NULL;
GCE(ceError = CTMapSystemError(ceError));
}
pDir = NULL;
cleanup:
if (pDir)
closedir(pDir);
CT_SAFE_FREE_STRING(srcPath);
CT_SAFE_FREE_STRING(destPath);
return ceError;
}
CENTERROR
CTReadNextLine(
FILE* fp,
PSTR *output,
PBOOLEAN pbEndOfFile
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
DynamicArray buffer;
const char nullTerm = '\0';
*pbEndOfFile = 0;
*output = NULL;
memset(&buffer, 0, sizeof(buffer));
GCE(ceError = CTSetCapacity(&buffer, 1, 100));
while(1)
{
if(fgets(buffer.data + buffer.size,
buffer.capacity - buffer.size, fp) == NULL)
{
if (feof(fp)) {
*pbEndOfFile = 1;
} else {
ceError = CTMapSystemError(errno);
GCE(ceError);
}
}
buffer.size += strlen(buffer.data + buffer.size);
if(*pbEndOfFile)
break;
if(buffer.size == buffer.capacity - 1 &&
((char *)buffer.data)[buffer.size - 1] != '\n')
GCE(ceError = CTSetCapacity(&buffer, 1, buffer.capacity * 2));
else
break;
}
GCE(ceError = CTArrayAppend(&buffer, 1, &nullTerm, 1));
*output = buffer.data;
buffer.data = NULL;
cleanup:
CTArrayFree(&buffer);
return ceError;
}
//The dynamic array must be initialized (at least zeroed out) beforehand
CENTERROR
CTReadLines(FILE *file, DynamicArray *dest)
{
CENTERROR ceError = CENTERROR_SUCCESS;
BOOLEAN eof = FALSE;
PSTR readLine = NULL;
CTArrayFree(dest);
while(!eof)
{
GCE(ceError = CTReadNextLine(file, &readLine, &eof));
GCE(ceError = CTArrayAppend(dest, sizeof(readLine), &readLine, 1));
readLine = NULL;
}
cleanup:
CT_SAFE_FREE_STRING(readLine);
return ceError;
}
CENTERROR
CTWriteLines(FILE *file, const DynamicArray *lines)
{
size_t i;
CENTERROR ceError = CENTERROR_SUCCESS;
for(i = 0; i < lines->size; i++)
{
PCSTR line = *(PCSTR *)CTArrayGetItem((DynamicArray*)lines, i,
sizeof(PCSTR));
GCE(ceError = CTFileStreamWrite(file, line, strlen(line)));
}
cleanup:
return ceError;
}
void
CTFreeLines(DynamicArray *lines)
{
size_t i;
for(i = 0; i < lines->size; i++)
{
CT_SAFE_FREE_STRING(*(PSTR *)CTArrayGetItem(
(DynamicArray*)lines, i, sizeof(PSTR)));
}
CTArrayFree(lines);
}
CENTERROR
CTSetCloseOnExec(
int fd)
{
long flags = fcntl(fd, F_GETFD);
if(flags < 0)
return CTMapSystemError(errno);
flags |= FD_CLOEXEC;
if(fcntl(fd, F_SETFD, flags) < 0)
return CTMapSystemError(errno);
return CENTERROR_SUCCESS;
}