/* caller will need to release the memory  for content buffer */
MI_Result ReadFileContent(_In_z_ const MI_Char *pFileName,
                          _Outptr_result_buffer_maybenull_(*pBufferSize) MI_Uint8 ** pBuffer,
                          _Out_ MI_Uint32 * pBufferSize,
                          _Outptr_result_maybenull_ MI_Instance **cimErrorDetails)
{
    FILE *fp;
    size_t result;
    unsigned long fileLen;
    size_t nSizeWritten;

    *pBuffer = 0;
    *pBufferSize = 0;
    fp = File_OpenT(pFileName, MI_T("rb"));
    if( fp == NULL)
    {
        return GetCimMIError(MI_RESULT_FAILED, cimErrorDetails, ID_ENGINEHELPER_OPENFILE_ERROR);
    }

    // Get File size
    result = fseek(fp, 0, SEEK_END);
    if(result)
    {
        File_Close(fp);
        return GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_ENGINEHELPER_FILESIZE_ERROR);
    }
    fileLen = ftell(fp);
    if(fileLen > MAX_MOFSIZE )
    {
MI_Result UpdateTask(
    _In_z_ MI_Char* taskName,
    _In_z_ MI_Char* taskTime,
    _In_ MI_Uint32 refreshFrequencyInSeconds,
    _Outptr_result_maybenull_ MI_Instance **extendedError)
{
    int retValue = -1;
    ssize_t read = 0;
    size_t readLength = 0, writeLength = 0;
	MI_Char *line = NULL, *lineToWrite = NULL, *taskInCrontab = NULL;
	FILE *cronFile = NULL, *cronFileTmp = NULL;
	MI_Uint32 errorCode = 0;

	if (extendedError == NULL)
	{
		return MI_RESULT_INVALID_PARAMETER;
	}
	*extendedError = NULL;


    // Preparation
    if (refreshFrequencyInSeconds > THIRTY_ONE_DAYS_IN_SECONDS)
    {
		refreshFrequencyInSeconds = THIRTY_ONE_DAYS_IN_SECONDS;
    }
    if (refreshFrequencyInSeconds < FIFTEEN_MINUTES_IN_SECONDS)
    {
		refreshFrequencyInSeconds = FIFTEEN_MINUTES_IN_SECONDS;
    }

    // PLAN 1 -- process each line of crontab file to a tmp file and then copy tmp file back
    // taskTime string is not used in Linux since we can simply register a task with frequency

	// Allocate memory
	line = (MI_Char *)DSC_malloc(UNIT_LINE_SIZE * sizeof(MI_Char), NitsHere());
	if (line == NULL)
	{
		errorCode = ID_LCMHELPER_MEMORY_ERROR;
		goto ExitWithError;
	}
    lineToWrite = (MI_Char *)DSC_malloc(UNIT_LINE_SIZE * sizeof(MI_Char), NitsHere());
	if (lineToWrite == NULL)
	{
		errorCode = ID_LCMHELPER_MEMORY_ERROR;
		goto ExitWithError;
	}
	taskInCrontab = (MI_Char *)DSC_malloc(UNIT_LINE_SIZE * sizeof(MI_Char), NitsHere());
	if (taskInCrontab == NULL)
	{
		errorCode = ID_LCMHELPER_MEMORY_ERROR;
		goto ExitWithError;
	}

	// Open files
	if (File_ExistT(CRON_FILE) != -1)
	{
		cronFile = File_OpenT(CRON_FILE, MI_T("r"));
		if (cronFile == NULL)
		{
			// Fail to open existing cron file should lead to error exit
			errorCode = ID_ENGINEHELPER_OPENFILE_ERROR;
			goto ExitWithError;
		}
	}
    cronFileTmp = File_OpenT(CRON_FILE_TMP, MI_T("w"));
    if (cronFileTmp == NULL)
	{
		// Fail to create tmp file should lead to error exit
		errorCode = ID_LCMHELPER_CREATEFILE_ERROR;
		goto ExitWithError;
    }

	// Read and process crontab file if it exists and opens appropriately
    while (cronFile != NULL && (read = readline(&line, &readLength, cronFile)) != -1)
    {
        retValue = TcsStrlcpy(lineToWrite, line, Tcslen(line)+1);
		retValue = sscanf(line, MI_T("%*s %*s %*s %*s %*s %*s %s"), taskInCrontab);
		if (retValue == 0)
		{
			// Ignore the bad line that does not comply with crontab file format
			continue;
		}
		else
		{
			if (Tcsncasecmp(taskName, taskInCrontab, Tcslen(taskName)) == 0)
			{
				// Ignore entry that duplicates registration of task
				continue;
			}
			else
			{
				// Write the entry to tmp file
				writeLength = fwrite(lineToWrite, 1, Tcslen(lineToWrite), cronFileTmp);
				if (writeLength != read)
				{
					errorCode = ID_LCMHELPER_WRITEFILE_ERROR;
					goto ExitWithError;
				}
			}
		}
    }
    if (readLength == -1)
	{
		// Deal memory failure in readline function
		errorCode = ID_ENGINEHELPER_READFILE_ERROR;
		goto ExitWithError;
	}

    // Add the task entry
    retValue = Stprintf(lineToWrite, UNIT_LINE_SIZE, MI_T("*/%d * * * * root %T\n"), refreshFrequencyInSeconds / 60, taskName);
	if (retValue == -1)
	{
		errorCode = ID_LCMHELPER_PRINTF_ERROR;
		goto ExitWithError;
	}
    writeLength = fwrite(lineToWrite, 1, Tcslen(lineToWrite), cronFileTmp);
	if (writeLength != Tcslen(lineToWrite))
	{
		errorCode = ID_LCMHELPER_WRITEFILE_ERROR;
		goto ExitWithError;
	}

	if (cronFile != NULL)
		File_Close(cronFile);
    File_Close(cronFileTmp);

    File_CopyT(CRON_FILE_TMP, CRON_FILE);
    File_RemoveT(CRON_FILE_TMP);    
    
    DSC_free(line);
    DSC_free(lineToWrite);
	DSC_free(taskInCrontab);

    return MI_RESULT_OK;

ExitWithError:
	// Close files and remove temp file if it exists
	if (cronFile)
		File_Close(cronFile);
	if (cronFileTmp)
		File_Close(cronFileTmp);
    if (File_ExistT(CRON_FILE_TMP) != -1)
        File_RemoveT(CRON_FILE_TMP);
	
	// Free memory allocations
	if (line != NULL)
		DSC_free(line);
	if (lineToWrite != NULL)
		DSC_free(lineToWrite);
	if (taskInCrontab != NULL)
		DSC_free(taskInCrontab);

	// Form rich CIM error
	if (errorCode != 0)
		return GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, extendedError, errorCode);
	else
		return MI_RESULT_FAILED;
}
int File_CopyT(_In_z_ const PAL_Char* src, _In_z_ const PAL_Char* dest)
{
    FILE* is = NULL;
    FILE* os = NULL;
    char buf[4096];

    /* Open input file */
    is = File_OpenT(src, PAL_T("rb"));
    if (!is)
        return -1;

#if defined(CONFIG_POSIX)
#ifndef CONFIG_ENABLE_WCHAR

    /* Unlink output file if it exists */
    if (access(dest, F_OK) == 0)
    {
        unlink(dest);
    }
#endif
#endif

    /* Open output file */
    os = File_OpenT(dest, PAL_T("wb"));
    if (!os)
    {
        File_Close(is);
        return -1;
    }

    /* Copy file */
    for (;;)
    {
#if defined(_MSC_VER)
        long n = (long)fread(buf, 1, sizeof(buf), is);
        long m;
#else
        ssize_t n = fread(buf, 1, sizeof(buf), is);
        ssize_t m;
#endif

        if (n <= 0)
            break;

#if defined(_MSC_VER)
        m  = (long)fwrite(buf, 1, n, os);
#else
        m  = (ssize_t)fwrite(buf, 1, n, os);
#endif

        if (m != n)
        {
            File_Close(is);
            File_Close(os);
            return -1;
        }
    }

    File_Close(is);
    File_Close(os);
    return 0;
}