in src/common/commonutils/FileUtils.c [943:1112]
static int ReplaceMarkedLinesInFileInternal(const char* fileName, const char* marker, const char* newline, char commentCharacter, bool preserveAccess, bool prepend, OsConfigLogHandle log)
{
const char* tempFileNameTemplate = "%s/~OSConfig.ReplacingLines%u";
char* tempFileName = NULL;
char* fileDirectory = NULL;
char* fileNameCopy = NULL;
FILE* fileHandle = NULL;
FILE* tempHandle = NULL;
int tempDescriptor = -1;
char* line = NULL;
long lineMax = sysconf(_SC_LINE_MAX);
long newlineLength = newline ? (long)strlen(newline) : 0;
bool skipLine = false;
bool replacedLine = false;
int status = 0;
if ((NULL == fileName) || (NULL == marker))
{
OsConfigLogError(log, "ReplaceMarkedLinesInFile called with invalid arguments");
return EINVAL;
}
else if (false == FileExists(fileName))
{
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile called for a file that does not exist: '%s'", fileName);
return 0;
}
else if (NULL == (line = malloc(lineMax + 1)))
{
OsConfigLogError(log, "ReplaceMarkedLinesInFile: out of memory");
return ENOMEM;
}
if (NULL != (fileNameCopy = DuplicateString(fileName)))
{
fileDirectory = dirname(fileNameCopy);
}
if (NULL != (tempFileName = FormatAllocateString(tempFileNameTemplate, fileDirectory ? fileDirectory : "/tmp", rand())))
{
if (NULL != (fileHandle = fopen(fileName, "r")))
{
// S_IRUSR (0400): Read permission, owner
// S_IWUSR (0200): Write permission, owner
if (-1 != (tempDescriptor = open(tempFileName, O_EXCL | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR)))
{
if (NULL != (tempHandle = fdopen(tempDescriptor, "w")))
{
// Write the new line to the beginning of the file if prepend is requested
if (prepend && newline && (newlineLength > 0))
{
if (EOF == fputs(newline, tempHandle))
{
status = (0 == errno) ? EPERM : errno;
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: cannot write prepended line to temporary file '%s' (%d)", tempFileName, status);
}
replacedLine = true;
}
while (NULL != fgets(line, lineMax + 1, fileHandle))
{
if (NULL != strstr(line, marker))
{
if ((commentCharacter != line[0]) && (EOL != line[0]) && (NULL != newline) && (1 < newlineLength))
{
if (replacedLine)
{
// Already replaced this line once
skipLine = true;
}
else
{
memset(line, 0, lineMax + 1);
memcpy(line, newline, (newlineLength > lineMax) ? lineMax : newlineLength);
skipLine = false;
replacedLine = true;
}
}
else if (commentCharacter == line[0])
{
skipLine = false;
}
else
{
skipLine = true;
}
}
if (false == skipLine)
{
if (EOF == fputs(line, tempHandle))
{
status = (0 == errno) ? EPERM : errno;
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: cannot write to temporary file '%s' (%d)", tempFileName, status);
}
}
memset(line, 0, lineMax + 1);
skipLine = false;
}
fclose(tempHandle);
}
else
{
close(tempDescriptor);
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: cannot open temporary file '%s', fdopen() failed (%d)", tempFileName, errno);
status = EACCES;
}
}
else
{
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: cannot open temporary file '%s', open() failed (%d)", tempFileName, errno);
status = EACCES;
}
fclose(fileHandle);
}
else
{
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: cannot read from '%s'", fileName);
status = EACCES;
}
}
else
{
OsConfigLogError(log, "ReplaceMarkedLinesInFile: out of memory");
status = ENOMEM;
}
FREE_MEMORY(line);
if ((0 == status) && (false == replacedLine) && (NULL != newline) && !prepend)
{
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: line '%s' did not replace any '%s' line, to be appended at end of '%s'",
newline, marker, fileName);
if (false == AppendPayloadToFile(tempFileName, newline, strlen(newline), log))
{
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: cannot append line '%s' at end of '%s'", newline, fileName);
}
}
if (0 == status)
{
if (preserveAccess)
{
if (0 != (status = RenameFileWithOwnerAndAccess(tempFileName, fileName, log)))
{
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: RenameFileWithOwnerAndAccess('%s' to '%s') returned %d", tempFileName, fileName, status);
}
}
else
{
if (0 != (status = RenameFile(tempFileName, fileName, log)))
{
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile: RenameFile('%s' to '%s') returned %d", tempFileName, fileName, status);
}
}
remove(tempFileName);
}
FREE_MEMORY(tempFileName);
FREE_MEMORY(fileNameCopy);
OsConfigLogInfo(log, "ReplaceMarkedLinesInFile('%s', '%s') returning %d", fileName, marker, status);
return status;
}