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

📄 tmfat32.c

📁 PNX1500上Fat32文件系统源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
            }
            else
            {
                // Keep looking
                start++;
                cluster = start;
            }
        }
    }

    // An error if we can't write anything

    if (0 == numWholeClusters)
        goto bail;

//    TMFAT_DEBUG5("numWholeClusters=%u,firstCluster=%u,cluster=%u,offset=%u,diskFull=%d\n", 
//                  numWholeClusters,firstCluster,cluster,offset,diskFull);

    *clus = cluster;
    *off = offset;
    *numWhole = numWholeClusters;
    *firstClus = firstCluster;
    *diskF = diskFull;
    return 0;

bail:
    return 1;
}

// Get or set cluster content through the DATA cache. Return the number of 
// bytes actually read or written. Return -1 if there is an error. Since 
// the number of bytes read or written may span several clusters return the 
// final cluster number and offset into that cluster. Writing may update
// the cluster chain in the FAT and it may run out of space on the disk.
// Reading/writing in the root directory for FAT12 or FAT16 is a special
// case because it is of fixed size and cached separately from the DATA
// cache. Returned offset can be bytesPerCluster. In that case:
//
//    reading -- we read the last byte in the last cluster
//    writing -- we wrote the last byte in the last cluster and any
//               subsequent writes will need to allocate a new cluster.

static Int32 UTIL_cluster_content(int op, UInt32 *clus, UInt32 *off, UInt8 *data, UInt32 nbyte)
{
    ptmFat32_FS_t   p = GFS;
    UInt8           *src;
    UInt8           *dst;
    Int32           actual = 0;
    UInt32          cluster;
    UInt32          temp;
    UInt32          offset;
    UInt32          size = 0;
    UInt32          i;
    UInt32          j;
    Bool            lastCluster;

    // Check parameter values

    TMFAT_ASSERT (data != Null);
    TMFAT_ASSERT (clus != Null);
    TMFAT_ASSERT (off != Null);
   
    cluster = *clus;
    offset = *off;
    
    if (nbyte == 0)
        return 0;
    
    if (p->fsType == tmFat32_FAT32)
    {
        if (cluster < p->rootDirCluster || cluster > p->maxCluster)
        {
            TMFAT_DEBUG3("UTIL_cluster_content: cluster %u is out of range (%u,%u)\n", 
                         cluster, p->rootDirCluster, p->maxCluster);
            return -1;
        }
    }
    else
    {
        if (cluster > p->maxCluster)
        {
            TMFAT_DEBUG3("UTIL_cluster_content: cluster %u is out of range (%u,%u)\n", 
                         cluster, p->rootDirCluster, p->maxCluster);
            return -1;
        }
    }
    
    if (offset > p->bytesPerCluster)
    {
        TMFAT_DEBUG2("UTIL_cluster_content: offset %u >= %u.\n", offset, p->bytesPerCluster);
        return -1;
    }
        
    if (op == GET_CLUSTER_CONTENT)
    {
        if (offset == p->bytesPerCluster)
        {
            TMFAT_DEBUG2("GET_CLUSTER_CONTENT offset == p->bytesPerCluster, offset=%u, cluster=%u\n",
                          offset, cluster); 
            return -1;
        }

        // Data comes from data cache, not from the media directly.
        // We can retrieve at most a cluster's worth of data at a 
        // time since that is the biggest allocation unit.

        dst = data;
        
        // Special case: reading from FAT12/FAT16 root directory
        
        if (p->fsType != tmFat32_FAT32 && cluster == 0)
        {
            src = p->rootDirCache;
            if (nbyte > p->rootDirNumSectors * p->dev->Info->bytesPerSector - offset)
            {
                TMFAT_DEBUG0("UTIL_cluster_content: Attemping to read beyond root directory.\n");
                goto done;
            }
            memcpy(dst, &src[offset], nbyte);
            actual = nbyte;
            offset += nbyte;
            goto done;
        }

        while (nbyte > 0)
        {
            if (!(src = UTIL_get_cluster_address(cluster)))
            {
                TMFAT_DEBUG1("GET_CLUSTER_CONTENT: UTIL_get_cluster_address(%d) failed.\n", cluster);
                goto done;
            }
            
            size = TMFAT_MIN(p->bytesPerCluster - offset, nbyte);
            memcpy(dst, &src[offset], size);
            nbyte -= size;
            actual += size;
            dst += size;
            offset += size;

            // Do we need to jump to the next cluster?
            if (offset == p->bytesPerCluster)
            {
                lastCluster = False;
                i = cluster;
                
                if (UTIL_fat_content(GET_FAT_ENTRY, cluster, 0, &temp))
                {
                    TMFAT_DEBUG1("GET_CLUSTER_CONTENT: UTIL_fat_content(%d) failed.\n", cluster);
                    goto done;
                }
                
                if (p->fsType == tmFat32_FAT32)
                {
                    cluster = temp & FAT32_CLUSTER_MASK;
                    if (cluster >= FAT32_EOC)
                        lastCluster = True;
                }
                else if (p->fsType == tmFat32_FAT16)
                {
                    cluster = temp & FAT16_CLUSTER_MASK;
                    if (cluster >= FAT16_EOC)
                        lastCluster = True;
                }
                else
                {
                    cluster = temp & FAT12_CLUSTER_MASK;
                    if (cluster >= FAT12_EOC)
                        lastCluster = True;
                }
                
                if (lastCluster)  // At end of file and file size is a multiple of cluster size
                {
                    cluster = i;
                    break;
                }
                else              // At the beginning of a cluster
                    offset = 0;
            }
        }
    }
    else
    {
        src = data;

        // Special case: writing to FAT12/FAT16 root directory
        
        if (p->fsType != tmFat32_FAT32 && cluster == 0)
        {
            UInt32  first;
            UInt32  last;

            if (offset == p->bytesPerCluster)
            {
                TMFAT_DEBUG2("Not FAT32 and SET_CLUSTER_CONTENT offset == p->bytesPerCluster, offset=%u, cluster=%u\n",
                              offset, cluster); 
                return -1;
            }

            dst = p->rootDirCache;
            if (nbyte > p->rootDirNumSectors * p->dev->Info->bytesPerSector - offset)
            {
                TMFAT_DEBUG0("UTIL_cluster_content: Attemping to write beyond root directory.\n");
                goto done;
            }
            memcpy(&dst[offset], src, nbyte);
            actual = nbyte;
            offset += nbyte;
            
            // Mark the affected sectors are dirty.
            
            first = offset / p->dev->Info->bytesPerSector;
            last = (offset + nbyte) / p->dev->Info->bytesPerSector;
            
            for (i = first; i <= last; i++)
                p->rootDirSectorDirty[i] = True;
                
            goto done;
        }
        
        if (op == SET_CLUSTER_CONTENT_NOCACHE)
        {
            // Avoid the cache, if possible. We may have to go through partial cluster
            // writes. Faster, but more complicated.
 
            tmErrorCode_t   status;
            UInt64          sec;
            Bool            diskFull;
            UInt32          numWholeClusters;    // Number of whole clusters to write
            UInt32          firstCluster;        // First cluster written
            UInt8           *src_data = src;

            /* Write as many sequential clusters at a time as possible. There are three
               cases when sequential clusters are available:

               (1) Allocate new clusters, e.g., when writing past end of file.
               (2) We're re-writing already allocated sequential clusters, e.g., a file 
                   opened as O_RDWR and entire write is before end of file.
               (3) Combination of (1) and (2). E.g., the write starts in the middle of
                   the file on clusters already allocated and we'll write past the end
                   of file allocating new clusters.

               We only handle cases (1) and (2). Case (3) is rare. It's equivalent to doing
               a write twice -- the first part as case (1) and the second part as case (2)
               so it's not a signifcant performance loss to break it up into two steps.
            */

//            TMFAT_DEBUG3("NOCACHE: cluster=%d,nbyte=%d,offset=%d\n", cluster, nbyte, offset);

            while (nbyte > 0)
            {
                if (UTIL_write_lookahead(nbyte, &cluster, &offset, &numWholeClusters, 
                                        &firstCluster, &diskFull))
                {
                    TMFAT_DEBUG0("UTIL_write_lookahead failed.\n");
                    goto done;
                }

                if (!numWholeClusters)
                {
                    TMFAT_DEBUG0("No whole clusters to write.\n");
                    TMFAT_ASSERT (numWholeClusters != 0);
                }

                // Determine starting sector

                sec = p->dataAreaBase + (firstCluster - p->rootDirCluster) * p->sectorsPerCluster;
                          
                // Clusters have been allocated. Now write them.

                size = numWholeClusters * p->bytesPerCluster;
                src_data = src;  // Where we're writing from
                status = p->dev->Write(p->dev->Info, 
                                       sec, // Starting sector
                                       numWholeClusters * p->sectorsPerCluster, // Number of sectors
                                       src);
                if (status != TM_OK)
                {
                    TMFAT_DEBUG0("UTIL_cluster_content: cache-less write failed.\n");
                    goto done;
                }

                // Because we didn't write through the DATA cache its contents no longer
                // match what's on disk. Make it the same.

                for (j = 0; j < numWholeClusters; j++)
                {
                    for (i = 0; i < p->dataNumClusters; i++)
                    {
                        if ((firstCluster + j) == p->dataCluster[i])
                        {
                            memcpy(UTIL_get_cluster_address(firstCluster + j),  // Destination
                                   &src_data[j * p->bytesPerCluster],           // Source
                                   p->bytesPerCluster);                         // Bytes                        
                            // Since it's already been written to disk it's no longer dirty.
                            p->dataClusterDirty[i] = False;
                        }
                    }
                }

                nbyte -= size;
                actual += size;
                src += size;

                // A full disk is not an error. We just report what we were able to write.

                if (diskFull)
                    goto done;
            }
        }
        else
        {
            // Write through the DATA cache, one cluster at a time. Simpler, but slower.
            
            while (nbyte > 0)
            {
                // Do we need to allocate another cluster? Clusters allocated for directories
                // must be cleared before writing to them. Do not allocate another cluster
                // if there is no more data to write.
                
                if (offset == p->bytesPerCluster)
                {
                    UInt32  cur_cluster = cluster;
                                    
                    if (UTIL_allocate_cluster(&cluster, cur_cluster, (op == SET_CLUSTER_CONTENT_CLEAR)))
                        goto done;
                    offset = 0;
                }

                if (!(dst = UTIL_get_cluster_address(cluster)))
                {
                    TMFAT_DEBUG1("UTIL_cluster_content: UTIL_get_cluster_address(%d) failed.\n", cluster);
                    goto done;
                }
                
                size = TMFAT_MIN(p->bytesPerCluster - offset, nbyte);
                
                memcpy(&dst[offset], src, size);
                nbyte -= size;
                actual += size;
                src += size;
                offset += size;
    
                // Mark it dirty
    
                for (i = 0; i < p->dataNumClusters; i++)
                {
                    if (cluster == p->dataCluster[i])
                    {
                        p->dataClusterDirty[i] = True;
                        break;
                    }
                }
            }
        }
    }

done:
    if (actual >= 0)
    {
        *clus = cluster;
        *off = offset;
    }
    return actual;
}


// Get or set a FAT entry. Return 0 on success.

static int UTIL_fat_content(int op, UInt32 entry, UInt32 value, UInt32 *result)
{
    tmErrorCode_t   status = TM_OK;
    ptmFat32_FS_t   p = GFS;
    UInt32          i;
    UInt64          sector = 0;
    UInt32          offset = 0;
    UInt32          index = 0;
    UInt32          entries_per_sector;
    UInt64          fatBase;
    UInt16          *pfat;
    UInt16          temp;

    if (entry > p->maxCluster)
    {
        TMFAT_DEBUG2("UTIL_fat_content: entry %d > %d.\n", entry, p->maxCluster);
        return 1;
    }
    if (op == GET_FAT_ENTRY)
    {
        TMFAT_ASSERT (result != Null);
    }

    fatBase = p->fatBase + p->activeFat * p->fatSize;
    if (p->fsType == tmFat32_FAT32)
        entries_per_sector = p->dev->Info->bytesPerSector / sizeof(UInt32);
    else if (p->fsType == tmFat32_FAT16)
        entries_per_sector = p->dev->Info->bytesPerSector / sizeof(UInt16);
    else
    {
        // FAT12 is entirely cached
        goto done;
    }

    sector = fatBase + entry / entries_per_sector;
    index = sector - fatBase;

⌨️ 快捷键说明

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