static int ReplaceMarkedLinesInFileInternal()

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;
}