Logo Search packages:      
Sourcecode: fuse-umfuse-fat version File versions  Download package

libfat.h

//This is "libfat.h" - Driver's constants, structures and prototypes    

#ifndef __BITS_LIBFAT_H
#define __BITS_LIBFAT_H

#ifndef __INSIDE_LIBFAT_H
#error "Never use <bits/libfat.h> directly; include <libfat.h> instead."
#endif
#include <endian.h>
#if __BYTE_ORDER == __BIG_ENDIAN
#include <byteswap.h>
#define EFW(X) bswap_16(X)
#define EFD(X) bswap_32(X)
#else
#define EFW(X) (X)
#define EFD(X) (X)
#endif

#include <config.h>
#include <glib.h>

/*    Maximum number of file opened */
#define MAX_OPENED_FILES      4096

 /* largest sector size */
#define MAX_SECTORSIZE        8192           

/* FAT directory entry size in bytes*/
#define FAT_DIRSIZE           32              

/* largest cluster size (sure?) */
#define MAX_CLUSTERSIZE       8192            

 /* largest MSDOS path length */
#define MAX_PATHLENGTH        128            

 /* largest directory (in sectors) */
#define MAX_DIRSIZE           64             

/* size of free cluster array in Volume_t */
#ifndef FCLUS_BUFSZ
#define FCLUS_BUFSZ 8192            
#endif

/* Maximum number of bytes per cluster: 32k, according to MS for max compatibility */
#define MAX_BYTES_PER_CLUSTER (32*1024) 

#ifdef LIBFAT_USE_MUTEX
#include <pthread.h>
#define fat_lock(V)     pthread_mutex_lock(&(V->fat_mutex))
#define fat_unlock(V)   pthread_mutex_unlock(&(V->fat_mutex))
#else
#define fat_lock(V) 
#define fat_unlock(V)
#endif

#ifndef ZERO_BFSZ
#define ZERO_BFSZ 8192
#endif


/* FAT Types */
typedef enum { FAT12, FAT16, FAT32 } FatType_t;

/* EOC (End Of Clusterchain) check macros.                               */
/* These expressions are true (nonzero) if the value of a FAT entry is   */
/* an EOC for the FAT type. An EOC indicates the last cluster of a file. */
#define  FAT12_ISEOC(EntryValue)  ((EntryValue) >= 0x0FF8)
#define  FAT16_ISEOC(EntryValue)  ((EntryValue) >= 0xFFF8)
#define  FAT32_ISEOC(EntryValue)  (((EntryValue) & 0x0FFFFFFF) >= 0x0FFFFFF8) //??????

#define  FAT12_ISFREE(EntryValue) (((EntryValue) & 0x0FFF) == 0x0)
#define  FAT16_ISFREE(EntryValue) (((EntryValue) & 0xFFFF) == 0x0)
#define  FAT32_ISFREE(EntryValue) (((EntryValue) & 0x0FFFFFFF) == 0x00000000)

#define      FAT12_EOC_VALUE  0x0FFF
#define  FAT16_EOC_VALUE      0xFFFF
#define      FAT32_EOC_VALUE  0x0FFFFFF8  //it was 0x0FFFFFFF but linux driver set it to F8



/* Bad cluster marks.                                                    */
/* Set a FAT entry to the FATxx_BAD value to mark the cluster as bad.    */
/*                                                                       */
/* The FAT file system specification says that to avoid confusion, no    */
/* FAT32 volume should ever be configured such that 0x0FFFFFF7 is an     */
/* allocatable cluster number. In fact an entry that would point to the  */
/* cluster 0x0FFFFFF7 would be recognised as Bad instead. Since values   */
/* greater or equal than 0x0FFFFFF8 are interpreted as EOC, I think we   */
/* can assume that the max cluster for a FAT32 volume is 0x0FFFFFF6.     */
/* That problem doesn't exist on FAT12 and FAT16 volumes, in fact:       */
/* 0x0FF7 = 4087 is greater than 4086 (max cluster for a FAT12 volume)   */
/* 0xFFF7 = 65527 is greater than 65526 (max cluster for a FAT16 volume) */
#define FAT12_BAD_VALUE 0x0FF7
#define FAT16_BAD_VALUE 0xFFF7
#define FAT32_BAD_VALUE 0x0FFFFFF7


#define  FAT12_ISBAD(EntryValue)  (EntryValue == 0x0FF7)
#define  FAT16_ISBAD(EntryValue)  (EntryValue == 0xFFF7)
#define  FAT32_ISBAD(EntryValue)  (EntryValue == 0x0FFFFFF7)

#define  FAT12_LEGALCLUS(EntryValue)  (!( (FAT12_ISEOC(EntryValue)) || (FAT12_ISFREE(EntryValue)) || (FAT12_ISBAD(EntryValue))))
#define  FAT16_LEGALCLUS(EntryValue)  (!( (FAT16_ISEOC(EntryValue)) || (FAT16_ISFREE(EntryValue)) || (FAT16_ISBAD(EntryValue))))
#define  FAT32_LEGALCLUS(EntryValue)  (!( (FAT32_ISEOC(EntryValue)) || (FAT32_ISFREE(EntryValue)) || (FAT32_ISBAD(EntryValue)))) 

/* FAT Date Encoding */
/*
 *      hi byte     |    low byte
 *  |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
 *  | | | | | | | | | | | | | | | | |
 *  \   7 bits    /\4 bits/\ 5 bits /
 *     year +80     month     day
*/
#define FILE_YEAR(dir) (( ((BYTE *) &((dir)->DIR_WrtDate))[1] >> 1) + 1980)
#define FILE_MONTH(dir) ((((((BYTE *) &((dir)->DIR_WrtDate))[1]&0x1) << 3) + (((BYTE *) &((dir)->DIR_WrtDate))[0] >> 5)))
#define FILE_DAY(dir) (((BYTE *) &((dir)->DIR_WrtDate))[0] & 0x1f)
      
/* FAT Time Encoding */
/*
 *      hi byte     |    low byte
 *  |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
 *  | | | | | | | | | | | | | | | | |
 *  \  5 bits /\  6 bits  /\ 5 bits /
 *     hour      minutes     sec*2
*/
#define FILE_HOUR(dir) (((BYTE *) &((dir)->DIR_WrtTime))[1] >> 3)
#define FILE_MINUTE(dir) ((((((BYTE *) &((dir)->DIR_WrtTime))[1]&0x7) << 3) + (((BYTE *) &((dir)->DIR_WrtTime))[0] >> 5)))
#define FILE_SEC(dir) ((((BYTE *) &((dir)->DIR_WrtTime))[0] & 0x1f) * 2)

/* FAT32 Boot Sector and BIOS Parameter Block                         */
/* This structure is used in all driver functions, even if the volume */
/* is FAT12 or FAT16. In fact some FAT32 fields are checked anyway    */
/* like BPB_FATSz32). So we load the boot sector from the disk, we    */
/* detect the FAT type and if it's a FAT32, we fill the following     */
/* struct as is, while if the volume is FAT12/FAT16 we copy in the    */
/* right position the appropriate (common) fields.                    */

typedef struct
{
  BYTE  BS_jmpBoot[3];        /* 0  Jump to boot code.                BS_jmpBoot */
  BYTE  BS_OEMName[8];        /* 3  OEM name & version.               BS_OEMName */
  WORD  BPB_BytsPerSec;       /* 11 Bytes per sector hopefully 512.   BPB_BytsPerSec */
  BYTE  BPB_SecPerClus;       /* 13 Cluster size in sectors.          BPB_SecPerClus */
  WORD  BPB_ResvdSecCnt;      /* 14 Number of reserved (boot) sectors. BPB_RsvdSecCount */
  BYTE  BPB_NumFATs;          /* 16 Number of FAT tables hopefully 2. BPB_NumFATs */
  WORD  BPB_RootEntCnt;       /* 17 Number of directory slots.        BPB_RootEntCnt */
  WORD  BPB_TotSec16;         /* 19 Total sectors on disk.            BPB_TotSec16 */
  BYTE  BPB_Media;            /* 21 Media descriptor=first byte of FAT. BPB_Media */
                        /*    0xF8 is the standard value for fixed media */
  WORD  BPB_FATSz16;          /* 22 Sectors in FAT.                   BPB_FATSz16 */
  WORD  BPB_SecPerTrk;        /* 24 Sectors/track.                    BPB_SecPerTrk */
  WORD  BPB_NumHeads;         /* 26 Heads.                            BPB_NumHeads */
  DWORD BPB_HiddSec;          /* 28 number of hidden sectors.         BPB_HiddSec */
  DWORD BPB_TotSec32;         /* 32 big total sectors.                BPB_TotSec32 */

  /* Here start the FAT32 specific fields (offset 36) */

  DWORD BPB_FATSz32;          /* 36 32bit count of sectors occupied by each FAT. BPB_FATSz16 must be 0    */
  WORD  BPB_ExtFlags;         /* 40 extension flags. Usually 0.
                                 * Bits 0-3: Zero-based number of active Fat. Valid if mirroring is disabled
                                 * Bits 4-6: Reserved
                                 * Bit 7: 0 = FAT mirrored into all FATs at runtime. 1 = only 1 FAT active
                                 * Bits 8-15: Reserved */

  WORD  BPB_FSVer;            /* 42 Version number of the FAT32 volume. For future extension. Must be 0:0 */
  DWORD BPB_RootClus;         /* 44 start cluster of root dir. Usually 2 */
  WORD  BPB_FSInfo;           /* 48 changeable global info */
  WORD  BPB_BkBootSec;        /* 50 back up boot sector. Recomended 6 */
  BYTE  BPB_Reserved[12];     /* 52 reserved for future expansion */

  /* The following fields are present also in a FAT12/FAT16 BPB, (labelblk_t)   */
  /* but at offset 36. In a FAT32 BPB they are at offset 64 instead. */

  BYTE BS_DrvNum;       /* 64 physical drive ?        */
  BYTE BS_Reserved1;          /* 65 reserved                */
  BYTE BS_BootSig;            /* 66 dos > 4.0 diskette. signature.      */
  DWORD BS_VolID;       /* 67 serial number           */
  BYTE BS_VolLab[11];         /* 71 disk label        */
  BYTE BS_FilSysType[8];      /* 82 FAT type                */
}
__attribute__ ((packed)) Bpb_t;

/* FAT12 and FAT16 Structure starting at Offset 36 of sector 0 */

typedef struct 
{
        BYTE BS_DrvNum;       /* 36 physical drive ?        */
        BYTE BS_Reserved1;    /* 37 reserved                */
        BYTE BS_BootSig;      /* 38 dos > 4.0 diskette. signature.      */
        DWORD BS_VolID;       /* 39 serial number           */
        BYTE BS_VolLab[11];   /* 43 disk label        */
        BYTE BS_FilSysType[8];      /* 54 FAT type                */
} 
__attribute__ ((packed)) labelblk_t;

/* FAT32 FSInfo Sector structure */
typedef struct
{
  DWORD FSI_LeadSig;          /* FSI_LeadSig.   0x41615252                                */
  BYTE  FSI_Reserved1[480];   /* FSI_Reserved1 (size 480 bytes should be 0)               */
  DWORD FSI_StrucSig;         /* FSI_StructSig. 0x61417272                          */
  DWORD FSI_Free_Count;       /* FSI_Free_Count.                                    */
  DWORD FSI_Nxt_Free;         /* FSI_Nxt_Free. Just an hint. 0xFFFFFFFF =  no hint available    */
  BYTE  FSI_Reserved2[12];    /* FSI_Reserved2                                      */
  DWORD FSI_TrailSig;         /* FSI_TrailSig.  0xAA550000                          */
}
__attribute__ ((packed)) FSInfo_t;

/* FAT 32-byte Directory Entry structure */
typedef struct
{
  BYTE  DIR_Name[11];         /*  0 file name (8+3) */
  BYTE  DIR_Attr;       /* 11 attribute byte */
  BYTE  DIR_NTRes;            /* 12 case of short filename */ /* MS says "reserved for NT */
  BYTE  DIR_CrtTimeTenth;     /* 13 creation time, milliseconds (?) */
  WORD  DIR_CrtTime;          /* 14 creation time */
  WORD  DIR_CrtDate;          /* 16 creation date */
  WORD  DIR_LstAccDate;       /* 18 last access date */
  WORD  DIR_FstClusHI;        /* 20 start cluster, Hi */
  WORD  DIR_WrtTime;          /* 22 time stamp */
  WORD  DIR_WrtDate;          /* 24 date stamp */
  WORD  DIR_FstClusLO;        /* 26 starting cluster number */
  DWORD DIR_FileSize;         /* 28 size of the file */
}
__attribute__ ((packed)) DirEntry_t;

// sfentry == DirEntry_t, value = DWORD
#define FIRST_CLUSTER(sfnentry, value) ((WORD *) &value)[0] = ((DirEntry_t) sfnentry).DIR_FstClusLO; ((WORD *) &value)[1] = ((DirEntry_t) sfnentry).DIR_FstClusHI

/* Special codes for the first byte of a directory entry (DIR_Name[0] */
#define FREEENT  0xE5 /* The directory entry is free             */
#define ENDOFDIR 0x00 /* This and the following entries are free */
#define DIRENT_ISFREE(D)      (((D) == FREEENT) || ((D) == ENDOFDIR))
#define DIRENT_ISLAST(D)      (D == ENDOFDIR)


/*    2bytes trailing signature that occupies the byte 510 and 511 of the boot sector,bkbootsector and FSinfo sector    */
#define BPB_TRAILSIG    0x55AA

/* Attributes for DIR_Attr    */
#define ATTR_READ_ONLY 0x1
#define ATTR_HIDDEN 0x2
#define ATTR_SYSTEM 0x4
#define ATTR_VOLUME_ID 0x8
#define ATTR_DIRECTORY 0x10
#define ATTR_ARCHIVE 0x20
#define ATTR_LONG_NAME ( ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID )

#define ATTR_ISDIR(D)   ( ( (D) & ATTR_DIRECTORY ) ==  ATTR_DIRECTORY )

/* values used by libfat. not correlated with fat file system values */

#define LIBFAT_DIRENT_FREE      0x01  //(0001)
#define LIBFAT_DIRENT_LASTFREE  0x09  //(1001)
#define LIBFAT_DIRENT_SFN       0x02  //(0010)
#define LIBFAT_DIRENT_LFN       0x04  //(0100)
#define LIBFAT_DIRENT_LFN_LAST  0x0C  //(1100)

#define LIBFAT_DIRENT_ISFREE(res)   ((res & LIBFAT_DIRENT_FREE) == LIBFAT_DIRENT_FREE)
#define LIBFAT_DIRENT_ISLASTFREE(res)     ((res & LIBFAT_DIRENT_LASTFREE) == LIBFAT_DIRENT_LASTFREE)
#define LIBFAT_DIRENT_ISSFN(res)    ((res & LIBFAT_DIRENT_SFN) == LIBFAT_DIRENT_SFN)
#define LIBFAT_DIRENT_ISLFN(res)    ((res & LIBFAT_DIRENT_LFN) == LIBFAT_DIRENT_LFN)
#define LIBFAT_DIRENT_ISLFNLAST(res)      ((res & LIBFAT_DIRENT_LFN_LAST) == LIBFAT_DIRENT_LFN_LAST)

/* values used in fat file system   */

#define LFN_LASTENTRY         0x40  /*    Last entry of a LFN set */
#define LFN_PADDING           0xFF  /*    padding for last LFN entry, if needed     */
#define LFN_NULL        0x00  /*    null terminator for last LFN entry  */

#define LFN_ISNULL(D)         ( D == LFN_NULL )
#define LFN_ISLAST(D)         ((D & LFN_LASTENTRY) == LFN_LASTENTRY)


/* FAT 32-byte Long File Name Directory Entry structure */
typedef struct
{
  BYTE LDIR_Ord;  /* Sequence number for slot        */
  WORD LDIR_Name1[5];   /* First 5 Unicode characters      */
  BYTE LDIR_Attr; /* Attributes, always 0x0F         */
  BYTE LDIR_Type; /* Reserved, always 0x00           */
  BYTE LDIR_Chksum;     /* Checksum of 8.3 name            */
  WORD LDIR_Name2[6];   /* 6 more Unicode characters       */
  WORD LDIR_FstClusLO;  /* First cluster number, must be 0 */
  WORD LDIR_Name3[2];   /* Last 2 Unicode characters       */
}
__attribute__ ((packed)) LfnEntry_t;

/* Linked likst structure for free clusters                       */

struct llist {
      int n;
      struct llist *next;
};

typedef struct llist FreeClus_t;

/* This structure stores all informations about a FAT volume.       */
/* It is the P structure (private data) for file system volume ops. */
typedef struct
{
  /* Data referring to the hosting block device */
  DWORD      blkDevFd;              /* File Descriptor of the block device hosting the volume   */
  mode_t     mode;                        /* Permissions for the volume                                           */
  uid_t      uid;                   /* user ID of owner */
  gid_t      gid;                   /* group ID of owner */
                                          
  /* Some precalculated data */

  DWORD      VolSig;                /* Must be FAT_VOLSIG for a valid volume   */
  FatType_t  FatType;               /* Can be FAT12, FAT16 or FAT32            */
  DWORD      DataClusters;          /* The total number of valid not reserved data clusters (last valid data cluster is dataclusters + 1 */
  DWORD      FirstDataSector;       /* The first sector of the data region, usually the beginning of rootdir in fat32     */
  DWORD      FirstRootCluster;      /* The first sector of FAT12/FAT16 root cluster, usually 2 (useless at the moment)   */
  DWORD    freecnt;                 /* The count of free clusters              */
  DWORD    nextfree;                /* The cluster number from which to start  */
                                    /* to search for free clusters, if known   */
  int numfats;    
  
  DWORD           freeclus[FCLUS_BUFSZ];
  int             fstfclus;
  int             fclusz;

  int bps;
  int spc;
  int bpc;
  DWORD fatsz;                            // It's ok to have an int here, cause a fat can have up to 2^28 DWORDs
  int rsvdbytecnt;                        // count of reserved bytes before fat 0
                                      
  off64_t bps64;  // bytes per sector    = V->Bpb.BPB_BytsPerSec;
  off64_t spc64;  // sectors per cluster        d=V->Bpb.BPB_SecPerClus;
  off64_t bpc64;  // bytes per cluster    = 
  off64_t fds64;  // first data serctor                       e=V->FirstDataSector;
  off64_t fdb64;        // first data byte 
                                    
  off64_t rootdir16off;
  int rootdir16sz;  
  
  /* a pthread mutex */
  pthread_mutex_t fat_mutex;                          
   
  /* for write0data (in seek) */
  char zerobuf[ZERO_BFSZ];

  /* FAT in fat12/16 volumes */
  char *fat;
        
  /* The BIOS Parameter Block of the volume (the long entry) */
  Bpb_t       Bpb;
  FSInfo_t    Fsi;
} Volume_t;

/*    Structure for dirents   */
typedef struct
{
      DWORD       clus;
      DWORD       off;
      off64_t           off1;
      off64_t           off2;
      off64_t           direntoff;
      int         len1;
      int               len2;
      int         len;
      LfnEntry_t  entry[21];
      int last;
} DirEnt_t;

/* The file structure stores all the informations about an open file. */      // VA CAMBIATA!!!!!!!!!!!!!!!!
typedef struct
{
  Volume_t  *V;               /* Pointer to the volume hosting the file */
  DWORD     ParentFstClus;   /* First cluster of the parent directory  */
  DWORD           ParentOffset;      /* Offset of the direntry    in parent file */
  DWORD           DirEntryClus;      /* Cluster containing the direntry             */
  DWORD     DirEntryOffset;  /* Offset of the dir entry in the cluster  */
//  DWORD     DirEntrySector;  /* Sector containing the directory entry  */
//  DWORD     DirEntrySecOff;  /* Byte offset of the 1st dir entry in sector */
//  off64_t AbsOffset;         /* Absolute offset in the fs of the 1st dir entry */
  DirEnt_t  D;        /* The file's directory entry             */
  DirEntry_t *DirEntry;        /* Pointer to sfn entry at the end of the chain */
  int     Mode;            /* File opening mode                      */
  char            FileName[511];           /* Utf8 filename                                       */
  int       rootdir;                /* 1 if the file refers to rootdir */
 
  /* The following fields refer to the byte position into the file */
  DWORD           CurClus;           /* Cluster where the file offset is atm  */
  DWORD           CurOff;                  /* Offset in the current cluster               */
  off64_t   CurAbsOff;         /* Absolute offset related to the beginning of the file    */
                                           /* Useful to know if we have to go ahead or restart from the beginning */
} File_t;

/*    Prototypes              */

/*    FAT access functions . these should be static so we dont have to declare them here        */
int fat32_read_entry(Volume_t *V, DWORD N, int FatNum, DWORD *Value);
#ifdef FATWRITE
int fat32_write_entry(Volume_t *V, DWORD N, int FatNum, DWORD Value);
int fat32_writen_entry(Volume_t *V, DWORD N, DWORD Value);
#endif
time_t fat_mktime2(DirEntry_t *D);
int fat_fill_time(WORD *Date, WORD *Time, time_t t);
int fat_isfree(Volume_t *V,DWORD value);
int fat_isbad(Volume_t *V,DWORD value);
int fat_iseoc(Volume_t *V,DWORD value);
int fat_legalclus(Volume_t *V,DWORD value);
DWORD fat_eocvalue(Volume_t *V);

/*    Directory entry functions                 */

int fat_populate_freelist(Volume_t *V);
DWORD   fat_getFreeCluster(Volume_t *V);
BYTE lfn_checksum(BYTE *name);
int analize_dirent(LfnEntry_t *D);
int  check_cluster_bound(Volume_t *V, DWORD *Cluster, DWORD *Offset);
int fetch_entry(Volume_t *V, DWORD *Cluster, DWORD *Offset, LfnEntry_t *D);
int fetch_next_direntry(Volume_t *V, DirEnt_t *D, DWORD *Cluster, DWORD *Offset);
int check_lfn_order(LfnEntry_t *Buffer, int bufsize);
int check_lfn_checksum(LfnEntry_t *Buffer, int bufsize);
WORD fetch_lfn_char(LfnEntry_t *D, int n);
int find_lfn_length( LfnEntry_t *D, int bufsize);
int extract_lfn_name( LfnEntry_t *Buffer, int bufsize, WORD *dest, int length);
int find_sfn_length( DirEntry_t *D, int bufsize);
int extract_sfn_name(DirEntry_t *D, int bufsize, char *name);
int fatentry_to_dirent(Volume_t *V, DirEnt_t *D, struct dirent *dirp);
int find_direntry(Volume_t *V, char *name, DWORD *Cluster, DWORD *Offset);
int traverse_path(Volume_t *V, gchar **parts, guint parts_len, DWORD *Cluster);
int find_file(Volume_t *V, const char *path, File_t *F, DWORD *Cluster, DWORD *Offset);
int fat_fat_sync(Volume_t *V);
#endif /* #ifdef _BITS_LIBFAT_H */

Generated by  Doxygen 1.6.0   Back to index