📄 libfat.c
字号:
/*OS libfat: library to access a fat32 filesystem Rev 0.3 aka "Beta version" Copyright (C) 2006-2007 Paolo Angelelli <angelell@cs.unibo.it> Acknowledgments to Salvatore Isaja, auctor of fat support for freedos32 since utf8/16 routines are taken from freedos32 unicode module, Renzo Davoli for bugfixes, big endian support and more. This software is free software; it can be (re)distributed under the terms of the GNU GPL General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. The Program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.*//*********************************************** * LIBFAT.c * Current known problems (limitations) :* - May have problems if the filesistem * was accessed before with MS-DOS or * something that does not support Long Filenames* - to be cont'd =)* TODO: fix function to create time to support timezone.* TODO: Refuse to mount if dirty bit is up***********************************************/#include <config.h>#include "libfat.h"#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#include <linux/unistd.h>#include <errno.h>#include <glib.h>#include <pthread.h>#include <execinfo.h>#include <stdarg.h>#include <dlfcn.h>#include <errno.h>#ifndef POPULATE_FREELIST_BUFSZ#define POPULATE_FREELIST_BUFSZ 8192#endifoff64_t byte_offset(Volume_t *V, DWORD Cluster, DWORD Offset) { off64_t clus = Cluster; off64_t off = Offset; if (Cluster == 1) if (V->FatType != FAT32) return (V->rootdir16off + off); /* else error */ return ( ((clus - 2) * V->bpc64) + V->fdb64 + off );}int fat_isfree(Volume_t *V,DWORD value) { if (V->FatType == FAT32) { return FAT32_ISFREE(value); } else if (V->FatType == FAT16) { return FAT16_ISFREE(value); } else { return FAT12_ISFREE(value); } return 0;}int fat_isbad(Volume_t *V,DWORD value) { if (V->FatType == FAT32) { return FAT32_ISBAD(value); } else if (V->FatType == FAT16) { return FAT16_ISBAD(value); } else { return FAT12_ISBAD(value); } return 0;}int fat_iseoc(Volume_t *V,DWORD value) { if (V->FatType == FAT32) { return FAT32_ISEOC(value); } else if (V->FatType == FAT16) { return FAT16_ISEOC(value); } else { return FAT12_ISEOC(value); } return 0;}int fat_legalclus(Volume_t *V,DWORD value) { if (V->FatType == FAT32) { return FAT32_LEGALCLUS(value); } else if (V->FatType == FAT16) { return FAT16_LEGALCLUS(value); } else { return FAT12_LEGALCLUS(value); } return 0;}DWORD fat_eocvalue(Volume_t *V) { if (V->FatType == FAT32) { return FAT32_EOC_VALUE; } else if (V->FatType == FAT16) { return FAT16_EOC_VALUE; } else { return FAT12_EOC_VALUE; } return 0;}static ssize_t readn(int fd, void *buf, size_t count) { int done = 0; int res; while (count > 0) { res = read(fd, (void *) &(((char *) buf)[done]), count); if (res <= 0) { // 0 indicates EOF, and it should never happen here. fprintf(stderr,"read() error. line: %d\n",__LINE__); return -1; } else { done += res; count -= res; } } return done; }static ssize_t writen(int fd, const char *buf, size_t count) { int done = 0; int res; while (count > 0) { res = write(fd, &(buf[done]), count); if (res < 0) { perror("write() error"); return -1; } else { done += res; count -= res; } } return done; }time_t fat_mktime(int s, int m, int h, int d, int mo, int y) { struct tm t; memset((char *) &t, 0, sizeof(struct tm)); t.tm_sec=s; /* seconds */ t.tm_min=m; /* minutes */ t.tm_hour=h; /* hours */ t.tm_mday=d; /* day of the month */ t.tm_mon=mo; /* month */ t.tm_year=y; /* year */ return mktime(&t);}time_t fat_mktime2(DirEntry_t *D) { int s=((((BYTE *) &(D->DIR_WrtTime))[0] & 0x1f) * 2); int m=((((((BYTE *) &(D->DIR_WrtTime))[1]&0x7) << 3) + (((BYTE *) &(D->DIR_WrtTime))[0] >> 5))); int h=(((BYTE *) &(D->DIR_WrtTime))[1] >> 3); int d=(((BYTE *) &(D->DIR_WrtDate))[0] & 0x1f); int mo=((((((BYTE *) &(D->DIR_WrtDate))[1]&0x1) << 3) + (((BYTE *) &(D->DIR_WrtDate))[0] >> 5))); int y=(( ((BYTE *) &(D->DIR_WrtDate))[1] >> 1) + 80); return fat_mktime(s,m,h,d,mo,y);}int fat_fill_time(WORD *Date, WORD *Time, time_t t) { // works ok. struct tm time; WORD date=0; WORD tim=0; WORD bmask3=0x07FF; WORD bmask2=0x01FF; WORD bmask1=0x001F; gmtime_r(&t, &time); date = (WORD) time.tm_mday; date &= bmask1; // to set 0 first 11 bits; date |= ((WORD) time.tm_mon) << 5; date &= bmask2; // to set 0 first 6 bits; date |= (((WORD) ((time.tm_year + 1900) -1980)) << 9); tim = (WORD) (time.tm_sec / 2); tim &= bmask1; tim |= (((WORD) (time.tm_min)) << 5); tim &= bmask3; tim |= (((WORD) (time.tm_hour)) << 11); *Time = EFW(tim); *Date = EFW(date); return 0; }/************************************************************************* Functions to access the FAT *************************************************************************//* FAT32 PRIMITIVES *//* The location of a valid cluster N into the FAT32 FAT *//* Returns 0 on success, or a negative error code on failure. *//* Called by fat32_read_entry and fat32_write_entry. *//* Put into Sector the sector number where the entry is, and *//* into EntryOffset the offset of the entry in the sector *//* FatNum = number of which fat we want to look into. 0 is 1st*//* N = the cluster we want sector and offset of. first is 2 */#if 0 // Useless atmstatic int fat32_cluster_entry(Volume_t *V, DWORD N, int FatNum, DWORD *Sector, DWORD *EntryOffset) { DWORD FATSz, EntryPerSec32; WORD bytspersec = EFW(V->Bpb.BPB_BytsPerSec);// DWORD entry; if (N > V->DataClusters + 1) return -ENXIO; FATSz = EFD(V->Bpb.BPB_FATSz32) * bytspersec;// entry = ( FatNum * FATSz ) + ( EFW(V->Bpb.BPB_ResvdSecCnt) * bytspersec ) + (N * 4); // printf("---- %u\n",entry); EntryPerSec32 = EFW(V->Bpb.BPB_BytsPerSec) / 4; /* fat32 entries are 4 bytes long */ *Sector = ( FatNum * FATSz ) + EFW(V->Bpb.BPB_ResvdSecCnt) + ( N / EntryPerSec32 ); *EntryOffset = ( (N % EntryPerSec32) * 4 ); return 0;}#endif/* The location of a valid cluster N into the FAT32 FAT *//* Returns the offset of the entry on success, or a negative *//* error code on failure. *//* FatNum = number of which fat we want to look into. 0 is 1st*//* N = the cluster we want sector and offset of. first is 2 */off64_t fat32_cluster_off(Volume_t *V, DWORD N, int FatNum) { off64_t rsvdbc = V->rsvdbytecnt; off64_t fatn = FatNum; off64_t fatsz = V->fatsz; off64_t entry = N; off64_t entrysz = 4; return ( rsvdbc + ( fatn * fatsz ) + ( entry * entrysz ));}/* Reads the value of the specified cluster entry in a FAT32 FAT. *//* Returns 0 on success, or a negative error code on failure. */int fat32_read_entry(Volume_t *V, DWORD N, int FatNum, DWORD *Value) { int Res;// DWORD Sector, EntryOffset; DWORD Entry; off64_t fatoffset; /* finding position */ if ((fatoffset = fat32_cluster_off(V, N, FatNum)) <= 0) return (int) fatoffset;// if ((Res = fat_readbuf(V, Sector)) < 0) return Res;/* lseek(SEEK_SET) */ if ( (Res = lseek64(V->blkDevFd, fatoffset, SEEK_SET)) < 0) { fprintf(stderr,"lseek() error in fat32_read_entry(). N: %u, off: %lld\n",N, fatoffset); return Res; }/* read() */ if ( (Res = readn(V->blkDevFd, &Entry, 4)) != 4) { fprintf(stderr,"readn() error in fat32_read_entry(). N: %u, off: %lld\n",N, fatoffset); return -1; } *Value = EFD(Entry) & 0x0FFFFFFF; return 0;}#ifdef FATWRITE/* Writes the value of the specified cluster entry in a FAT32 FAT. *//* Returns 0 on success, or a negative error code on failure. */int fat32_write_entry(Volume_t *V, DWORD N, int FatNum, DWORD Value) { int Res;// DWORD Sector, EntryOffset; DWORD val; off64_t off; Value &= 0x0FFFFFFF; if ((Res = fat32_read_entry(V, N, FatNum, &val)) != 0) { perror("fat32_write_entry error"); return -1; } val &= 0xF0000000; Value = Value | val; /* finding position */ if ((off = fat32_cluster_off(V, N, FatNum)) <= 0) return (int) off;/* lseek(SEEK_SET) */ if ( (Res = lseek64(V->blkDevFd, off, SEEK_SET)) < 0) { perror("lseek() error in fat32_read_entry()"); return -1; }/* write() */ Value=EFD(Value); if ( (Res = writen(V->blkDevFd, (char*) &Value, 4)) != 4) { perror("writen() error in fat32_read_entry()"); return -1; } return 0;}/* Writes the value of the specified cluster entry in all FAT32 FATs of the volume V *//* Returns 0 on success, or a negative error code on failure. */int fat32_writen_entry(Volume_t *V, DWORD N, DWORD Value) { int i; int numfats = V->numfats; for (i=0; i < numfats; i++) { if ( fat32_write_entry(V, N, i, Value) != 0) { perror("fat32_write_entry error in fat32_writen_entry()"); return -1; } } return 0;}/* Unlinks (marks as free) all the clusters of the chain starting from *//* cluster Cluster (that must be part of a valid chain) until the EOC. */static int fat32_unlinkn(Volume_t *V, DWORD Cluster) { int Res; DWORD Next; int i =0; if ((fat_isfree(V,Cluster)) || (FAT32_ISEOC(Cluster))) return 0; if (FAT32_ISBAD(Cluster)) return -1; do { /* Read the next entry in the chain */ if ( (Res = fat32_read_entry(V, Cluster, 0, &Next)) != 0 ) { fprintf(stderr,"unlinkn() error cycle: %d Line: %d",i, __LINE__); return -1; } /* Update every FAT in the volume */ if ( (Res = fat32_writen_entry(V, Cluster, 0)) != 0 ) { fprintf(stderr,"unlinkn() error cycle: %d Line: %d",i,__LINE__); return -1; } /* Update FSInfo Sector values */ V->freecnt++;// if (Cluster < V->nextfree ) ->nextfree = Cluster; Cluster = Next; i++; } while (!(FAT32_ISEOC(Next))); fprintf(stderr,"unkinkn: freecnt: %u, i:%d\n", V->freecnt,i); return 0;}/* FAT16 PRIMITIVES */static int fat16_read_entry(Volume_t *V, DWORD N, int FatNum, DWORD *Value) { *Value = EFW(((WORD*) V->fat)[N]); return 0; }static int fat16_write_entry(Volume_t *V, DWORD N, int FatNum, DWORD Value) { WORD val; val = Value; val = EFW(val); ((WORD*) V->fat)[N] = val; return 0;}static int fat16_unlinkn(Volume_t *V, DWORD Cluster) { int Res; DWORD Next; int i = 0; if ((FAT16_ISFREE(Cluster)) || (FAT16_ISEOC(Cluster))) return 0; if (FAT16_ISBAD(Cluster)) return -1; do { /* Read the next entry in the chain */ if ( (Res = fat16_read_entry(V, Cluster, 0, &Next)) != 0 ) { fprintf(stderr,"unlinkn() error cycle: %d Line: %d",i, __LINE__); return -1; } /* Update every FAT in the volume */ if ( (Res = fat16_write_entry(V, Cluster, 0, 0)) != 0 ) { fprintf(stderr,"unlinkn() error cycle: %d Line: %d",i,__LINE__); return -1; } /* Update FSInfo Sector values */ V->freecnt++;// if (Cluster < V->nextfree ) ->nextfree = Cluster; Cluster = Next; i++; } while (!(FAT16_ISEOC(Next))); return 0;}/* FAT12 PRIMITIVES */static int fat12_read_entry(Volume_t *V, DWORD N, int FatNum, DWORD *Value) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -