找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1037|回复: 1
收起左侧

FreeRTOS文件系统备份机制

[复制链接]
ID:736501 发表于 2020-4-23 21:44 | 显示全部楼层 |阅读模式
#include <sys/ioctl.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "ite/itp.h"
#include "ctrlboard.h"
#include "scene.h"

#ifdef _WIN32
    #define BACKUP_DRIVE CFG_TEMP_DRIVE
#else
    #define BACKUP_DRIVE "C"
#endif
#define CONFIG_DRIVE    CFG_PUBLIC_DRIVE
#define DEFAULT_DRIVE   CFG_PRIVATE_DRIVE
#define MAX_BACKUP_COUNT 110

#define NEED_RESTORE_FROM_BACKUP    1
#define NEED_RESTORE_DEFAULT        2

typedef struct BACKUP_FILE_PATH
{
    char path[256];
}BACKUP_FILE_PATH;

static BACKUP_FILE_PATH *gtBackupList[MAX_BACKUP_COUNT] = { 0 };
static int              gBackupFileCount = 0;
static int              gBackupDiskType = 0;


static int _GetDriveDiskMode();
/**
* Used to traverse default drive backup section to generate backup file list.
*
* @return none.
*/
static void _TraverseFileList(char* path)
{
    DIR           *dir;
    struct dirent *ent;
    int ret = 0;

    dir = opendir(path);

    if (dir == NULL)
    {
        return;
    }

    //Traverse to get backup list
    while ((ent = readdir(dir)) != NULL)
    {
        if (strcmp(ent->d_name, ".") == 0)
            continue;

        if (strcmp(ent->d_name, "..") == 0)
            continue;

        if (ent->d_type == DT_DIR)
        {
            char dirPath[PATH_MAX];
            char srcPath[PATH_MAX];
            int ret1;

            strcpy(dirPath, path);
            strcat(dirPath, ent->d_name);
            strcat(dirPath, "/");

            _TraverseFileList(dirPath);
        }
        else
        {
            if (ent->d_name[0] != '~')
            {
                char filePath[PATH_MAX];
                strcpy(filePath, path);
                strcat(filePath, ent->d_name);
                gtBackupList[gBackupFileCount] = (BACKUP_FILE_PATH*) malloc(sizeof(BACKUP_FILE_PATH));
                strcpy(gtBackupList[gBackupFileCount]->path, &filePath[strlen(DEFAULT_DRIVE ":/backup/" CONFIG_DRIVE "/")]);
                gBackupFileCount++;
            }
        }
    }

    if (dir)
    {
        if (closedir(dir))
        {
            printf("close dir(%s) is failed\n", path);
        }
    }
}

/**
* Used to save files from source to destination partition.
* @param srcPartition   source partition drive.
* @param dstPartition   destination partition drive.
* @return none.
*/
static void _FileSyncFile(char *srcPartition, char *dstPartition)
{
    int i = 0;
    unsigned char   filePath[256] = { 0 };
    ITCFileStream   srcStream = { 0 };
    ITCFileStream   dstStream = { 0 };
    unsigned char   *pFileBuffer = NULL;

    for (i = 0; i < gBackupFileCount; i++)
    {               
        sprintf(filePath, "%s:/%s", srcPartition, gtBackupList[i]->path);
        if (itcFileStreamOpen(&srcStream, filePath, false))
        {
            printf("%s(%d): abnormal error\n", __FILE__, __LINE__);
            assert(0);
        }

        pFileBuffer = (unsigned char*) malloc(srcStream.stream.size);
        assert(pFileBuffer);
        itcStreamRead(&srcStream, pFileBuffer, srcStream.stream.size);
        itcFileStreamClose((ITCStream*) &srcStream);

        sprintf(filePath, "%s:/%s", dstPartition, gtBackupList[i]->path);
        if (itcFileStreamOpen(&dstStream, filePath, true))
        {
            printf("%s(%d): abnormal error\n", __FILE__, __LINE__);
            assert(0);
        }

        itcStreamWrite(&dstStream, pFileBuffer, srcStream.stream.size);
        itcFileStreamClose((ITCStream*) &dstStream);
        free(pFileBuffer);
    }
#if defined(CFG_NOR_ENABLE) && CFG_NOR_CACHE_SIZE > 0
    ioctl(ITP_DEVICE_NOR, ITP_IOCTL_FLUSH, NULL);
#endif
}

/**
* Used to check the init backup/source partition.
*
* @return result of check backup/source partition.
*/
static int _CheckBackupStatus(void)
{
    int i = 0;
    unsigned char   filePath[256] = { 0 };
    ITCFileStream   srcStream = { 0 };
    ITCFileStream   backupStream = { 0 };
    int             result = 0;

    //check drive validation, backup_special_file is used to identify the partition belonging to
    //public or backup partition.
    if (itcFileStreamOpen(&srcStream, CONFIG_DRIVE ":/backup_special_file", false))
    {
        //right public drive
        printf("right public drive volume number\n");
    }
    else
    {
        printf("invalid drive volume number, need to repartition public\n");
        result = NEED_RESTORE_FROM_BACKUP;
    }
    itcFileStreamClose((ITCStream*) &srcStream);
    if (result)
    {
        return result;
    }

    for (i = 0; i < gBackupFileCount; i++)
    {
        sprintf(filePath, "%s:/%s", CONFIG_DRIVE, gtBackupList[i]->path);
        if (itcFileStreamOpen(&srcStream, filePath, false))
        {
            //partition is broken.
            printf("--------------Public partition is crashed------------------\n");
            result = NEED_RESTORE_FROM_BACKUP;
            //usleep(1 * 1000 * 1000);
        }
        itcFileStreamClose((ITCStream*) &srcStream);

        sprintf(filePath, "%s:/%s", BACKUP_DRIVE, gtBackupList[i]->path);
        if (itcFileStreamOpen(&backupStream, filePath, false))
        {
            //not existed or partition is broken.
            printf("--------------Backup partition is crashed or not existed------------------\n");
            result = NEED_RESTORE_DEFAULT;
            //usleep(1 * 1000 * 1000);
        }
        itcFileStreamClose((ITCStream*) &backupStream);

        if (result != 0)
        {
            break;
        }
    }

    return result;
}

/**
* Used to reinit the corrupted partition.
* @param volume   reinit volume number.
* @return none.
*/
static int _ReinitFatVolume(int volume)
{
    ITPDriveStatus* driveStatusTable;
    ITPDisk         remountDiskType[ITP_MAX_DRIVE];   
    int             remountDiskCount = 0;
    int             diskMode = _GetDriveDiskMode();

    int i = 0, j = 0;
    ioctl(ITP_DEVICE_DRIVE, ITP_IOCTL_DISABLE, NULL);
    usleep(100 * 1000);

    ioctl(ITP_DEVICE_DRIVE, ITP_IOCTL_GET_TABLE, &driveStatusTable);

    //Try to find any other mounted device on FAT and remove them to prvent such device
    //been assigned lower volume number.
    for (i = 0; i < ITP_MAX_DRIVE; i++)
    {
        ITPDriveStatus* driveStatus = &driveStatusTable[i];
        if (driveStatus->disk != diskMode && driveStatus->device == ITP_DEVICE_FAT && driveStatus->avail == 1)
        {
            for (j = 0; j < remountDiskCount; j++)
            {
                if (remountDiskType[j] == driveStatus->disk)
                {
                    break;
                }
            }
            if (j >= remountDiskCount)
            {
                remountDiskType[remountDiskCount] = driveStatus->disk;
                remountDiskCount++;
            }
            printf("disc: %d, device: %d, ava: %d, name: %s\n", driveStatus->disk, driveStatus->device, driveStatus->avail, driveStatus->name);
        }
    }

    printf("unmount all volume except NOR, count: %d\n", remountDiskCount);
    for (j = 0; j < remountDiskCount; j++)
    {
        ioctl(ITP_DEVICE_FAT, ITP_IOCTL_UNMOUNT, (void*)remountDiskType[j]);
    }

    ioctl(ITP_DEVICE_FAT, ITP_IOCTL_UNMOUNT, (void*)diskMode);
    ioctl(ITP_DEVICE_FAT, ITP_IOCTL_FORCE_MOUNT, (void*)diskMode);
    ioctl(ITP_DEVICE_FAT, ITP_IOCTL_FORMAT, (void*)volume);
    ioctl(ITP_DEVICE_DRIVE, ITP_IOCTL_ENABLE, NULL);

    printf("remount all volume except NOR, count: %d\n", remountDiskCount);
    for (j = 0; j < remountDiskCount; j++)
    {
        ioctl(ITP_DEVICE_FAT, ITP_IOCTL_MOUNT, (void*)remountDiskType[j]);
    }
}

static int _GetDriveDiskMode()
{
    int i;
    ITPDriveStatus* driveStatusTable;
    ioctl(ITP_DEVICE_DRIVE, ITP_IOCTL_GET_TABLE, &driveStatusTable);

    for (i = 0; i < ITP_MAX_DRIVE; i++)
    {
        ITPDriveStatus* driveStatus = &driveStatusTable[i];
        if (driveStatus->device == ITP_DEVICE_FAT && driveStatus->avail == 1)
        {
            return driveStatus->disk;
        }
    }
    return ITP_DISK_NOR;
}

/**
* Used to init backup feature.
*
* @return none.
*/
void BackupInit(void)
{
    char VolumeBase = 0;
    char VolumeTarget = 0;

    _TraverseFileList(DEFAULT_DRIVE ":/backup/" CONFIG_DRIVE "/");

#if 0 //print backup file path
    {
        int i = 0;
        for (i = 0; i < gBackupFileCount; i++)
        {
            printf("[%d]: %s\n", i, gtBackupList[i]->path);
        }
    }
#endif

    switch (_CheckBackupStatus())
    {
        case NEED_RESTORE_FROM_BACKUP:
        {
            printf("restore from backup........\n");
            VolumeBase = 0;
            VolumeTarget = 0;
            memcpy(&VolumeBase, CFG_PRIVATE_DRIVE, 1);
            memcpy(&VolumeTarget, CFG_PUBLIC_DRIVE, 1);
            _ReinitFatVolume((int)VolumeTarget - (int)VolumeBase);
            ugRestoreDir(CONFIG_DRIVE ":", DEFAULT_DRIVE ":/backup/" CONFIG_DRIVE);
#if defined(CFG_NOR_ENABLE) && CFG_NOR_CACHE_SIZE > 0
            ioctl(ITP_DEVICE_NOR, ITP_IOCTL_FLUSH, NULL);
#endif
            _FileSyncFile(BACKUP_DRIVE, CONFIG_DRIVE);
            break;
        }
        case NEED_RESTORE_DEFAULT:
        {
            ITCFileStream   specialStream = { 0 };
            printf("need restore to default\n");
            VolumeBase = 0;
            VolumeTarget = 0;
            memcpy(&VolumeBase, CFG_PRIVATE_DRIVE, 1);
            memcpy(&VolumeTarget, BACKUP_DRIVE, 1);
            _ReinitFatVolume((int)VolumeTarget - (int)VolumeBase);
            ugRestoreDir(BACKUP_DRIVE ":", DEFAULT_DRIVE ":/backup/" CONFIG_DRIVE);
            if (itcFileStreamOpen(&specialStream, BACKUP_DRIVE ":/backup_special_file", true))
            {
                assert(0);
            }
            itcStreamWrite(&specialStream, "1234", sizeof("1234"));
            itcFileStreamClose((ITCStream*) &specialStream);

#if defined(CFG_NOR_ENABLE) && CFG_NOR_CACHE_SIZE > 0
            ioctl(ITP_DEVICE_NOR, ITP_IOCTL_FLUSH, NULL);
#endif
            break;
        }
        default:
            printf("noting to do...\n");
            break;
    }
}

/**
* Used to sync source and backup partition file.
* @return none.
*/
void BackupSyncFile(void)
{
    int i = 0, index = 0;
    unsigned char   srcFilePath[256] = { 0 };
    unsigned char   backupFilePath[256] = { 0 };
    ITCFileStream   srcStream = { 0 };
    ITCFileStream   backupStream = { 0 };
    //Fix race condition bug.
    //unsigned char   *pSrcDataBuf = NULL;
    //unsigned char   *pBackupDataBuf = NULL;

    for (i = 0; i < gBackupFileCount; i++)
    {
        //Assign initial pointer of pSrcDataBuf to avoid race condition.
        unsigned char   *pSrcDataBuf = NULL;
        unsigned char   *pBackupDataBuf = NULL;
        bool bUpdateFile = false;

        sprintf(srcFilePath, "%s:/%s", CONFIG_DRIVE, gtBackupList[i]->path);
        if (itcFileStreamOpen(&srcStream, srcFilePath, false))
        {
            printf("%s(%d): abnormal error\n", __FILE__, __LINE__);
            assert(0);
        }

        sprintf(backupFilePath, "%s:/%s", BACKUP_DRIVE, gtBackupList[i]->path);
        if (itcFileStreamOpen(&backupStream, backupFilePath, false))
        {
            printf("%s(%d): abnormal error\n", __FILE__, __LINE__);
            assert(0);
        }

        //src file need to copy to dst
        if (srcStream.stream.size != backupStream.stream.size)
        {
            bUpdateFile = true;
        }
        else
        {
            pSrcDataBuf = (unsigned char*) malloc(srcStream.stream.size);
            if (pSrcDataBuf == NULL)
            {
                printf("%s(%d): abnormal error\n", __FILE__, __LINE__);
                assert(0);
            }
            itcStreamRead(&srcStream, pSrcDataBuf, srcStream.stream.size);

            pBackupDataBuf = (unsigned char*) malloc(backupStream.stream.size);
            if (pBackupDataBuf == NULL)
            {
                printf("%s(%d): abnormal error\n", __FILE__, __LINE__);
                assert(0);
            }
            itcStreamRead(&backupStream, pBackupDataBuf, backupStream.stream.size);

            if (memcmp(pSrcDataBuf, pBackupDataBuf, srcStream.stream.size))
            {
                bUpdateFile = true;
            }
        }

        if (bUpdateFile)
        {
            printf("sync file: %s, %s\n", srcFilePath, backupFilePath);
            itcFileStreamClose((ITCStream*) &backupStream);

            if (itcFileStreamOpen(&backupStream, backupFilePath, true))
            {
                printf("%s(%d): abnormal error\n", __FILE__, __LINE__);
                assert(0);
            }

            if (pSrcDataBuf == NULL)
            {
                pSrcDataBuf = (unsigned char*) malloc(srcStream.stream.size);
                if (pSrcDataBuf == NULL)
                {
                    printf("%s(%d): abnormal error\n", __FILE__, __LINE__);
                    assert(0);
                }
                itcStreamRead(&srcStream, pSrcDataBuf, srcStream.stream.size);
            }
            itcStreamWrite(&backupStream, pSrcDataBuf, srcStream.stream.size);
        }
        itcFileStreamClose((ITCStream*) &srcStream);
        itcFileStreamClose((ITCStream*) &backupStream);
        if (bUpdateFile)
        {
#if defined(CFG_NOR_ENABLE) && CFG_NOR_CACHE_SIZE > 0
            ioctl(ITP_DEVICE_NOR, ITP_IOCTL_FLUSH, NULL);
#endif
        }
        if (pSrcDataBuf)
        {
            free(pSrcDataBuf);
        }
        if (pBackupDataBuf)
        {
            free(pBackupDataBuf);
        }
    }
}

/**
* Used to restore the backup files to source.
* @return none.
*/
void BackupRestore(void)
{
    printf("restore backup file to source....\n");
    _FileSyncFile(BACKUP_DRIVE, CONFIG_DRIVE);
}

/**
* Used to save the source files to backup.
* @return none.
*/
void BackupSave(void)
{
    printf("backup file save....\n");
    _FileSyncFile(CONFIG_DRIVE, BACKUP_DRIVE);
}

/**
* Used to destroy backup feature.
*
* @return none.
*/
void BackupDestroy(void)
{
    int i = 0;
    printf("destroy backup feature....\n");

    for (i = 0; i < gBackupFileCount; i++)
        if (gtBackupList[i])
            free(gtBackupList[i]);

    gBackupFileCount = 0;
}


回复

使用道具 举报

ID:736501 发表于 2020-4-23 21:54 | 显示全部楼层
大家快来讨论一下这个备份机制设计怎么样吧
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表