⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat_fat_operations.c

📁 DOS/Windows FAT 文件系统实现源码
💻 C
字号:
/* *  fat_fat_operations.c * *  General operations on File Allocation Table * *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru> * *  @(#) $Id: fat_fat_operations.c,v 1.22 2002/02/11 16:42:14 jack Exp $ */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <stdlib.h>#include <assert.h>#include <rtems/libio_.h>#include "fat.h"#include "fat_fat_operations.h"/* fat_scan_fat_for_free_clusters -- *     Allocate chain of free clusters from Files Allocation Table * * PARAMETERS: *     mt_entry - mount table entry *     chain    - the number of the first allocated cluster (first cluster  *                in  the chain) *     count    - count of clusters to allocate (chain length) * * RETURNS: *     RC_OK on success, or error code if error occured (errno set  *     appropriately) * *      */int fat_scan_fat_for_free_clusters(    rtems_filesystem_mount_table_entry_t *mt_entry,    unsigned32                           *chain,    unsigned32                            count,    unsigned32                           *cls_added,    unsigned32                           *last_cl     ){    int            rc = RC_OK;    fat_fs_info_t *fs_info = mt_entry->fs_info;    unsigned32     cl4find = 2;    unsigned32     next_cln = 0;    unsigned32     save_cln = 0;     unsigned32     data_cls_val = fs_info->vol.data_cls + 2;    unsigned32     i = 2;      *cls_added = 0;        if (count == 0)        return rc;            if ((fs_info->vol.type & FAT_FAT32) &&         (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE))          cl4find = fs_info->vol.next_cl;      /*      * fs_info->vol.data_cls is exactly the count of data clusters      * starting at cluster 2, so the maximum valid cluster number is      * (fs_info->vol.data_cls + 1)     */    while (i < data_cls_val)    {        rc = fat_get_fat_cluster(mt_entry, cl4find, &next_cln);        if ( rc != RC_OK )        {            if (*cls_added != 0)                fat_free_fat_clusters_chain(mt_entry, (*chain));            return rc;        }            if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE)         {            /*             * We are enforced to process allocation of the first free cluster             * by separate 'if' statement because otherwise undo function              * wouldn't work properly             */            if (*cls_added == 0)            {                *chain = cl4find;                rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);                if ( rc != RC_OK )                {                    /*                      * this is the first cluster we tried to allocate so no                      * cleanup activity needed                      */                     return rc;                 }            }            else            {                  /* set EOC value to new allocated cluster */                rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);                if ( rc != RC_OK )                {                    /* cleanup activity */                    fat_free_fat_clusters_chain(mt_entry, (*chain));                    return rc;                 }                rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find);                if ( rc != RC_OK )                {                    /* cleanup activity */                    fat_free_fat_clusters_chain(mt_entry, (*chain));                    /* trying to save last allocated cluster for future use */                    fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);                    fat_buf_release(fs_info);                    return rc;                 }            }              save_cln = cl4find;            (*cls_added)++;            /* have we satisfied request ? */            if (*cls_added == count)            {                if (fs_info->vol.type & FAT_FAT32)                 {                    fs_info->vol.next_cl = save_cln;                    if (fs_info->vol.free_cls != 0xFFFFFFFF)                        fs_info->vol.free_cls -= (*cls_added);                }                        *last_cl = save_cln;                    fat_buf_release(fs_info);                return rc;              }          }        i++;        cl4find++;          if (cl4find >= data_cls_val)            cl4find = 2;    }    if (fs_info->vol.type & FAT_FAT32)    {         fs_info->vol.next_cl = save_cln;        if (fs_info->vol.free_cls != 0xFFFFFFFF)            fs_info->vol.free_cls -= (*cls_added);        }            *last_cl = save_cln;    fat_buf_release(fs_info);    return RC_OK;    } /* fat_free_fat_clusters_chain -- *     Free chain of clusters in Files Allocation Table. * * PARAMETERS: *     mt_entry - mount table entry *     chain    - number of the first cluster in  the chain  * * RETURNS: *     RC_OK on success, or -1 if error occured (errno set appropriately) */int fat_free_fat_clusters_chain(    rtems_filesystem_mount_table_entry_t *mt_entry,    unsigned32                            chain    ){    int            rc = RC_OK, rc1 = RC_OK;    fat_fs_info_t *fs_info = mt_entry->fs_info;    unsigned32     cur_cln = chain;     unsigned32     next_cln = 0;     unsigned32     freed_cls_cnt = 0;        while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)    {        rc = fat_get_fat_cluster(mt_entry, cur_cln, &next_cln);        if ( rc != RC_OK )        {            if ((fs_info->vol.type & FAT_FAT32) &&                 (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE))                fs_info->vol.free_cls += freed_cls_cnt;            fat_buf_release(fs_info);                return rc;        }            rc = fat_set_fat_cluster(mt_entry, cur_cln, FAT_GENFAT_FREE);        if ( rc != RC_OK )            rc1 = rc;        freed_cls_cnt++;        cur_cln = next_cln;    }    if (fs_info->vol.type & FAT_FAT32)    {        fs_info->vol.next_cl = chain;        if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)            fs_info->vol.free_cls += freed_cls_cnt;    }        fat_buf_release(fs_info);    if (rc1 != RC_OK)        return rc1;    return RC_OK; }/* fat_get_fat_cluster -- *     Fetches the contents of the cluster (link to next cluster in the chain)  *     from Files Allocation Table. * * PARAMETERS: *     mt_entry - mount table entry *     cln      - number of cluster to fetch the contents from *     ret_val  - contents of the cluster 'cln' (link to next cluster in  *                the chain)  * * RETURNS: *     RC_OK on success, or -1 if error occured *     and errno set appropriately */intfat_get_fat_cluster(    rtems_filesystem_mount_table_entry_t *mt_entry,    unsigned32                            cln,    unsigned32                           *ret_val    ){    int                     rc = RC_OK;    register fat_fs_info_t *fs_info = mt_entry->fs_info;    bdbuf_buffer           *block0 = NULL;    unsigned32              sec = 0;    unsigned32              ofs = 0;    /* sanity check */    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )        set_errno_and_return_minus_one(EIO);    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +           fs_info->vol.afat_loc;    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);    rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);    if (rc != RC_OK)        return rc;    switch ( fs_info->vol.type )    {        case FAT_FAT12:            /*              * we are enforced in complex computations for FAT12 to escape CPU             * align problems for some architectures             */            *ret_val = (*((unsigned8 *)(block0->buffer + ofs)));            if ( ofs == (fs_info->vol.bps - 1) )            {                rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,                                     &block0);                if (rc != RC_OK)                    return rc;                *ret_val |= (*((unsigned8 *)(block0->buffer)))<<8;            }            else            {                  *ret_val |= (*((unsigned8 *)(block0->buffer + ofs + 1)))<<8;            }            if ( FAT_CLUSTER_IS_ODD(cln) )                *ret_val = (*ret_val) >> FAT12_SHIFT;            else                *ret_val = (*ret_val) & FAT_FAT12_MASK;            break;        case FAT_FAT16:            *ret_val = *((unsigned16 *)(block0->buffer + ofs));            *ret_val = CF_LE_W(*ret_val);            break;        case FAT_FAT32:            *ret_val = *((unsigned32 *)(block0->buffer + ofs));            *ret_val = CF_LE_L(*ret_val);            break;        default:            set_errno_and_return_minus_one(EIO);            break;    }    return RC_OK;}/* fat_set_fat_cluster -- *     Set the contents of the cluster (link to next cluster in the chain) *     from Files Allocation Table. * * PARAMETERS: *     mt_entry - mount table entry *     cln      - number of cluster to set contents to *     in_val   - value to set  * * RETURNS: *     RC_OK on success, or -1 if error occured *     and errno set appropriately */intfat_set_fat_cluster(    rtems_filesystem_mount_table_entry_t *mt_entry,    unsigned32                            cln,    unsigned32                            in_val    ){    int                rc = RC_OK;    fat_fs_info_t     *fs_info = mt_entry->fs_info;    unsigned32         sec = 0;    unsigned32         ofs = 0;    unsigned16         fat16_clv = 0;    unsigned32         fat32_clv = 0;    bdbuf_buffer      *block0 = NULL;      /* sanity check */    if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )        set_errno_and_return_minus_one(EIO);    sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +           fs_info->vol.afat_loc;    ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);      rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);    if (rc != RC_OK)        return rc;    switch ( fs_info->vol.type )    {        case FAT_FAT12:            if ( FAT_CLUSTER_IS_ODD(cln) )            {                fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT));                *((unsigned8 *)(block0->buffer + ofs)) =                         (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F;                *((unsigned8 *)(block0->buffer + ofs)) =                         (*((unsigned8 *)(block0->buffer + ofs))) |                         (unsigned8)(fat16_clv & 0x00FF);                fat_buf_mark_modified(fs_info);                                if ( ofs == (fs_info->vol.bps - 1) )                {                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,                                         &block0);                    if (rc != RC_OK)                        return rc;                     *((unsigned8 *)(block0->buffer)) &= 0x00;                       *((unsigned8 *)(block0->buffer)) =                             (*((unsigned8 *)(block0->buffer))) |                             (unsigned8)((fat16_clv & 0xFF00)>>8);                                          fat_buf_mark_modified(fs_info);                }                else                {                    *((unsigned8 *)(block0->buffer + ofs + 1)) &= 0x00;                                  *((unsigned8 *)(block0->buffer + ofs + 1)) =                             (*((unsigned8 *)(block0->buffer + ofs + 1))) |                             (unsigned8)((fat16_clv & 0xFF00)>>8);                }              }            else            {                fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK));                *((unsigned8 *)(block0->buffer + ofs)) &= 0x00;                *((unsigned8 *)(block0->buffer + ofs)) =                         (*((unsigned8 *)(block0->buffer + ofs))) |                         (unsigned8)(fat16_clv & 0x00FF);                                        fat_buf_mark_modified(fs_info);                          if ( ofs == (fs_info->vol.bps - 1) )                {                    rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,                                         &block0);                    if (rc != RC_OK)                        return rc;                    *((unsigned8 *)(block0->buffer)) =                             (*((unsigned8 *)(block0->buffer))) & 0xF0;                      *((unsigned8 *)(block0->buffer)) =                             (*((unsigned8 *)(block0->buffer))) |                             (unsigned8)((fat16_clv & 0xFF00)>>8);                                                fat_buf_mark_modified(fs_info);                        }                else                {                    *((unsigned8 *)(block0->buffer + ofs + 1)) =                         (*((unsigned8 *)(block0->buffer + ofs + 1))) & 0xF0;                    *((unsigned8 *)(block0->buffer + ofs+1)) =                            (*((unsigned8 *)(block0->buffer + ofs+1))) |                            (unsigned8)((fat16_clv & 0xFF00)>>8);                }              }            break;        case FAT_FAT16:            *((unsigned16 *)(block0->buffer + ofs)) =                     (unsigned16)(CT_LE_W(in_val));            fat_buf_mark_modified(fs_info);                    break;        case FAT_FAT32:            fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));            *((unsigned32 *)(block0->buffer + ofs)) =             (*((unsigned32 *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000));            *((unsigned32 *)(block0->buffer + ofs)) =                    fat32_clv | (*((unsigned32 *)(block0->buffer + ofs)));                        fat_buf_mark_modified(fs_info);            break;        default:            set_errno_and_return_minus_one(EIO);            break;    }    return RC_OK;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -