📄 fat_sup.c
字号:
/* * FAT general support * * Copyright(C) 2001 * Camilo Alejandro Arboleda * * The contents of this file are distributed under the GNU General * Public License version 2. * * As a special exception, when this code is included in the RTEMS * operating system, linking other files with RTEMS objects including * this code does not cause the resulting executable application to * be covered by the GNU General Public License. This exception does * not however invalidate any other reasons why the executable file might * be covered by the GNU General Public License. */#include <sys/types.h> /* for mkdir */#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <dirent.h>#include <rtems.h>#include <rtems/libio.h>#include "fat.h"#include "mtd.h"extern rtems_filesystem_location_info_t rtems_filesystem_current;extern rtems_filesystem_location_info_t rtems_filesystem_root;extern int rtems_libio_is_file_open(void *node_access);extern void strlwr(char *);#ifndef set_errno_and_return_minus_one#define set_errno_and_return_minus_one( _error ) \ do { errno = (_error); return -1; } while(0)#endif#define rtems_filesystem_is_separator( _ch ) \ ( ((_ch) == '/') || ((_ch) == '\\') || ((_ch) == '\0'))#define fat_is_not_valid_char( c ) \ (((c < 'A') || (c > 'Z')) && ((c < 'a') || (c > 'z')) && ((c < '0') || (c >'9')) && (c!='.'))#define fat_is_valid_char( c ) \ (((c >= 'A') && (c =< 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <='9')) || (c=='.'))#define upchar( c ) ( ((c >= 'a') && (c <= 'z')) ? (c-0x20):(c))#define lowchar( c ) ( ((c >= 'A') && (c <= 'Z')) ? (c+0x20):(c)) #define SECTORSIZE 512extern FAT_jnode_t *fat_root_dir;extern FAT_jnode_t *fat_tail;/* Adds a node to open nodes chain */voidadd_node(FAT_jnode_t *node){ fat_tail->next = node; node->next = NULL; node->back = fat_tail; if (node->parent) node->parent->reference++; fat_tail = node;}/* Removes a node from open nodes chain */voiddel_node(FAT_jnode_t *node){ FAT_jnode_t *index; FAT_jnode_t *parent = node->parent; index = fat_root_dir; if (node->reference > 0) return; while (index->next) { if (index->next == node) { index->next = node->next; if (index->next) { index->next->back = index; } else { fat_tail = index; } free(node); return; } index = index->next; } if (parent) { parent->reference--; if (parent->reference <= 0) { del_node(parent); } }}/* Reads a block from FAT area */voidread_fat_block(int cluster, fat_geom_t *geom){ unsigned char buffer[SECTORSIZE * 2]; unsigned offset2; int i; int fd = geom->fd; geom->fat_cache.offset = cluster; switch (geom->type) { case 0x04: case 0x06: /* FAT 16 */ if (geom->fat_cache.entries == NULL) { geom->fat_cache.entries = calloc(256,sizeof(unsigned short)); if (!geom->fat_cache.entries) exit(1); /* Error */ geom->fat_cache.size = 256; } offset2 = geom->bytes_per_sect + (cluster * 2); lseek( fd, offset2, SEEK_SET ); read( fd, buffer, geom->bytes_per_sect ); for (i = 0;i < geom->fat_cache.size; i++) geom->fat_cache.entries[i] = * (unsigned short*)(buffer + i*2); break; case 0x01: /* FAT 12 */ if (geom->fat_cache.entries == NULL) { geom->fat_cache.size = geom->sectors_per_fat * SECTORSIZE; geom->fat_cache.entries = calloc(geom->fat_cache.size,sizeof(unsigned char)); if (!geom->fat_cache.entries) exit(1); /* Error */ lseek(fd, SECTORSIZE, SEEK_SET); read(fd,geom->fat_cache.entries,geom->fat_cache.size); } break; default: break; }}/* Search one free cluster in disk */unsignedsearch_free_cluster(fat_geom_t *geom){ fat_block_t *fat_block = &(geom->fat_cache); unsigned o2,t1, t2, cluster; /* FAT 12 */ if (geom->type == 0x01) { for (cluster = 2; cluster < geom->fat_entries ; cluster++) { o2 = (cluster / 2) * 3; t1 = *(unsigned *)( ((char *)fat_block->entries) + o2) & 0xfff; t2 = (*(unsigned *)( ((char *)fat_block->entries) + o2) & 0xfff000) >> 12; if (t1 == 0) return cluster; cluster++; if (t2 == 0) return cluster; } /* end for */ return -1; } return -1;}/* */voidsave_fat( fat_geom_t *geom){ fat_block_t *fat_block = &(geom->fat_cache); unsigned offset = 0; unsigned offset2 = 0; unsigned fat_size; unsigned mask = 1; int fd = geom->fd; fat_size = SECTORSIZE * geom->sectors_per_fat; if (geom->type == 0x01) { offset = SECTORSIZE; while (mask) { if (fat_block->changed & mask ) { /* Write first fat */ lseek(fd, offset, SEEK_SET); write(fd, ((char *)fat_block->entries) + offset2, SECTORSIZE); if (geom->total_FATs > 1) { /* Write second fat */ lseek(fd, offset+fat_size, SEEK_SET); write(fd, ((char *)fat_block->entries) + offset2, SECTORSIZE); } } offset += SECTORSIZE; offset2 += SECTORSIZE; fat_block->changed &= ~mask; /* set as no changed */ mask <<= 1; /* Next sector */ } } else { if (!fat_block->changed) return; offset = geom->bytes_per_sect + (fat_block->offset * 2); lseek(fd, offset, SEEK_SET); write(fd, fat_block->entries, 256); if (geom->total_FATs > 1) { lseek(fd, offset+fat_size, SEEK_SET); write(fd, fat_block->entries, 256); } fat_block->changed = 0; }};/* Changes the value of fat entry "cluster" with "new_value" */voidupdate_cluster(unsigned cluster, unsigned new_value, fat_geom_t *geom){ fat_block_t *fat_block = &(geom->fat_cache); unsigned o2,t1, bit1,bit2; unsigned tmp_offset; if (geom->type == 0x01) { /* FAT 12 */ o2 = (cluster / 2) * 3; t1 = *(unsigned *)( ((char *)fat_block->entries) + o2); if (cluster & 0x01) { new_value &= 0x00000fff; new_value <<= 12; t1 &= 0xff000fff; t1 |= new_value; } else { new_value &= 0x00000fff; t1 &= 0xfffff000; t1 |= new_value; } *(unsigned *)( ((char *)fat_block->entries) + o2) = t1; bit1 = 1 << (o2 / SECTORSIZE); bit2 = 1 << ( (o2 + 3) / SECTORSIZE); fat_block->changed |= (bit1 | bit2); } else { /* FAT 16 */ if ( fat_block->offset <= cluster && (fat_block->offset + 256) > cluster ) { fat_block->entries[cluster-fat_block->offset] = new_value; } else { if (fat_block->changed) save_fat( geom); tmp_offset = cluster - cluster % 256; read_fat_block(tmp_offset,geom); fat_block->entries[cluster-fat_block->offset] = new_value; } fat_block->changed = 1; }}/* Add a new cluster to a chain */voidadd_cluster(unsigned last_cluster, unsigned new_cluster, fat_geom_t *geom){ /* Make last_cluster point new cluster */ update_cluster(last_cluster,new_cluster, geom); /* Make new_cluster last cluster in chain */ update_cluster(new_cluster,0xfff, geom);}/* Search the next cluster in a cluster chain */unsignedsearch_next_cluster(int cluster, fat_geom_t *geom){ unsigned tmp_offset; unsigned o2; unsigned t1; fat_block_t *fat_block = &(geom->fat_cache); /* FAT 12 */ if (geom->type == 0x01) { o2 = (cluster / 2) * 3; if (cluster & 0x01) t1 = (*(unsigned *)( ((char *)fat_block->entries) + o2) & 0xfff000) >> 12; else t1 = *(unsigned *)( ((char *)fat_block->entries) + o2) & 0xfff; if (t1 > 0xff0) t1 |= 0xf000; return t1; } /* FAT 16 */ if ( fat_block->offset <= cluster && (fat_block->offset + 256) > cluster ) { return fat_block->entries[cluster-fat_block->offset]; } tmp_offset = cluster - cluster % 256; read_fat_block(tmp_offset,geom); return fat_block->entries[cluster-fat_block->offset];}/* Find the cluster correspondig to current cluster */intfind_cluster(FAT_jnode_t *node, int offset, unsigned *cluster){ int new_cluster = node->current_cluster; int offset2 = node->cache_offset - node->cache_offset % node->geometry->cluster_size; *cluster = node->current_cluster; offset &= 0xfffffe00; if ( (offset < node->cache_offset) || (node->cache_offset < 0) ) { /* Previous cluster or no cluster at all */ *cluster = node->st_ino; offset2 = 0; } while ( (offset2+node->geometry->cluster_size) <= offset ) { new_cluster = search_next_cluster(*cluster, node->geometry); if (new_cluster > 0xfff0) return -1; /* */ *cluster = new_cluster; offset2 += node->geometry->cluster_size; } return *cluster;}/* Reads a block from disk */intread_root_block(FAT_jnode_t *node, fat_geom_t *geom, int offset){ int disk_offset; int fd = geom->fd; /* check block alignment */ if ( (offset & 0x1ff) != 0 ) return -1; disk_offset = geom->root_dir_offset + offset; if (disk_offset >= geom->data_offset) return -1; lseek(fd,disk_offset,SEEK_SET); read(fd,node->cache,SECTORSIZE); node->current_cluster = 0; node->cache_offset = offset - offset % SECTORSIZE; return 0;}/* Reads a block from disk */intread_block(FAT_jnode_t *node, fat_geom_t *geom, int offset){ int cluster = node->current_cluster; int offset2 = node->cache_offset - node->cache_offset % geom->cluster_size; int disk_offset; int fd = geom->fd; /* check block alignment */ if ( (offset & 0x1ff) != 0 ) return -1; if ( (offset < node->cache_offset) || (node->cache_offset < 0) ) { /* Previous cluster or no cluster at all */ cluster = node->st_ino; offset2 = 0; } while ( (offset2+geom->cluster_size) <= offset ) { cluster = search_next_cluster(cluster, geom);/* if ( (cluster >= 0xfff8) && (cluster <= 0xffff) ) return cluster; */ if (cluster > 0xfff0) return -1; /* Invalid off-set */ offset2 += geom->cluster_size; }/* if (cluster == node->current_cluster) return 0; */ disk_offset = cluster * geom->cluster_size + geom->first_cluster_offset + offset % geom->cluster_size; lseek(fd,disk_offset,SEEK_SET); read(fd,node->cache,SECTORSIZE); node->current_cluster = cluster; node->cache_offset = offset - offset % SECTORSIZE; return 0;}/*------------------------------------------------------------------- * Not optimized fat read. It reads byte by byte and does not handle * errors */intfat_read (FAT_jnode_t *node, char *buffer, int count){ int byte_offset = node->offset & 0x1ff; int offset = node->offset & 0xfffffe00; int moved = 0; int bytes, buffer_offset = 0; int status; if ( (node->type == FAT_FILE) && (count + node->offset > node->size) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -