2008-11-06 23:53:46 +03:00
# ifndef _FAT_H
# define _FAT_H
# include <linux/buffer_head.h>
# include <linux/string.h>
# include <linux/nls.h>
# include <linux/fs.h>
# include <linux/mutex.h>
# include <linux/msdos_fs.h>
/*
* vfat shortname flags
*/
# define VFAT_SFN_DISPLAY_LOWER 0x0001 /* convert to lowercase for display */
# define VFAT_SFN_DISPLAY_WIN95 0x0002 /* emulate win95 rule for display */
# define VFAT_SFN_DISPLAY_WINNT 0x0004 /* emulate winnt rule for display */
# define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */
# define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */
2009-06-03 21:34:22 +04:00
# define FAT_ERRORS_CONT 1 /* ignore error and continue */
# define FAT_ERRORS_PANIC 2 /* panic on error */
# define FAT_ERRORS_RO 3 /* remount r/o on error */
2008-11-06 23:53:46 +03:00
struct fat_mount_options {
uid_t fs_uid ;
gid_t fs_gid ;
unsigned short fs_fmask ;
unsigned short fs_dmask ;
unsigned short codepage ; /* Codepage for shortname conversions */
char * iocharset ; /* Charset used for filename input/display */
unsigned short shortname ; /* flags for shortname display/create rule */
unsigned char name_check ; /* r = relaxed, n = normal, s = strict */
2009-06-03 21:34:22 +04:00
unsigned char errors ; /* On error: continue, panic, remount-ro */
2008-11-06 23:53:46 +03:00
unsigned short allow_utime ; /* permission for setting the [am]time */
unsigned quiet : 1 , /* set = fake successful chmods and chowns */
showexec : 1 , /* set = only set x bit for com/exe/bat */
sys_immutable : 1 , /* set = system files are immutable */
dotsOK : 1 , /* set = hidden and system files are named '.filename' */
isvfat : 1 , /* 0=no vfat long filename support, 1=vfat support */
utf8 : 1 , /* Use of UTF-8 character set (Default) */
unicode_xlate : 1 , /* create escape sequences for unhandled Unicode */
numtail : 1 , /* Does first alias have a numeric '~1' type tail? */
flush : 1 , /* write things quickly */
nocase : 1 , /* Does this need case conversion? 0=need case conversion*/
usefree : 1 , /* Use free_clusters for FAT32 */
2008-11-06 23:53:55 +03:00
tz_utc : 1 , /* Filesystem timestamps are in UTC */
rodir : 1 ; /* allow ATTR_RO for directory */
2008-11-06 23:53:46 +03:00
} ;
# define FAT_HASH_BITS 8
# define FAT_HASH_SIZE (1UL << FAT_HASH_BITS)
/*
* MS - DOS file system in - core superblock data
*/
struct msdos_sb_info {
unsigned short sec_per_clus ; /* sectors/cluster */
unsigned short cluster_bits ; /* log2(cluster_size) */
unsigned int cluster_size ; /* cluster size */
unsigned char fats , fat_bits ; /* number of FATs, FAT bits (12 or 16) */
unsigned short fat_start ;
unsigned long fat_length ; /* FAT start & length (sec.) */
unsigned long dir_start ;
unsigned short dir_entries ; /* root dir start & entries */
unsigned long data_start ; /* first data sector */
unsigned long max_cluster ; /* maximum cluster number */
unsigned long root_cluster ; /* first cluster of the root directory */
unsigned long fsinfo_sector ; /* sector number of FAT32 fsinfo */
struct mutex fat_lock ;
unsigned int prev_free ; /* previously allocated cluster number */
unsigned int free_clusters ; /* -1 if undefined */
unsigned int free_clus_valid ; /* is free_clusters valid? */
struct fat_mount_options options ;
struct nls_table * nls_disk ; /* Codepage used on disk */
struct nls_table * nls_io ; /* Charset used for input and display */
const void * dir_ops ; /* Opaque; default directory operations */
int dir_per_block ; /* dir entries per block */
int dir_per_block_bits ; /* log2(dir_per_block) */
int fatent_shift ;
struct fatent_operations * fatent_ops ;
2009-06-07 21:44:36 +04:00
struct inode * fat_inode ;
2008-11-06 23:53:46 +03:00
spinlock_t inode_hash_lock ;
struct hlist_head inode_hashtable [ FAT_HASH_SIZE ] ;
} ;
# define FAT_CACHE_VALID 0 /* special case for valid cache */
/*
* MS - DOS file system inode data in memory
*/
struct msdos_inode_info {
spinlock_t cache_lru_lock ;
struct list_head cache_lru ;
int nr_caches ;
/* for avoiding the race between fat_free() and fat_get_cluster() */
unsigned int cache_valid_id ;
2008-11-06 23:53:57 +03:00
/* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */
loff_t mmu_private ; /* physically allocated size */
2008-11-06 23:53:46 +03:00
int i_start ; /* first cluster or 0 */
int i_logstart ; /* logical first cluster */
int i_attrs ; /* unused attribute bits */
loff_t i_pos ; /* on-disk position of directory entry or 0 */
struct hlist_node i_fat_hash ; /* hash by i_location */
struct inode vfs_inode ;
} ;
struct fat_slot_info {
loff_t i_pos ; /* on-disk position of directory entry */
loff_t slot_off ; /* offset for slot or de start */
int nr_slots ; /* number of slots + 1(de) in filename */
struct msdos_dir_entry * de ;
struct buffer_head * bh ;
} ;
static inline struct msdos_sb_info * MSDOS_SB ( struct super_block * sb )
{
return sb - > s_fs_info ;
}
static inline struct msdos_inode_info * MSDOS_I ( struct inode * inode )
{
return container_of ( inode , struct msdos_inode_info , vfs_inode ) ;
}
2008-11-06 23:53:54 +03:00
/*
* If - > i_mode can ' t hold S_IWUGO ( i . e . ATTR_RO ) , we use - > i_attrs to
* save ATTR_RO instead of - > i_mode .
2008-11-06 23:53:55 +03:00
*
* If it ' s directory and ! sbi - > options . rodir , ATTR_RO isn ' t read - only
* bit , it ' s just used as flag for app .
2008-11-06 23:53:54 +03:00
*/
static inline int fat_mode_can_hold_ro ( struct inode * inode )
{
struct msdos_sb_info * sbi = MSDOS_SB ( inode - > i_sb ) ;
mode_t mask ;
2008-11-06 23:53:55 +03:00
if ( S_ISDIR ( inode - > i_mode ) ) {
if ( ! sbi - > options . rodir )
return 0 ;
2008-11-06 23:53:54 +03:00
mask = ~ sbi - > options . fs_dmask ;
2008-11-06 23:53:55 +03:00
} else
2008-11-06 23:53:54 +03:00
mask = ~ sbi - > options . fs_fmask ;
if ( ! ( mask & S_IWUGO ) )
return 0 ;
return 1 ;
}
2008-11-06 23:53:54 +03:00
/* Convert attribute bits and a mask to the UNIX mode. */
static inline mode_t fat_make_mode ( struct msdos_sb_info * sbi ,
u8 attrs , mode_t mode )
{
2008-11-06 23:53:55 +03:00
if ( attrs & ATTR_RO & & ! ( ( attrs & ATTR_DIR ) & & ! sbi - > options . rodir ) )
2008-11-06 23:53:54 +03:00
mode & = ~ S_IWUGO ;
if ( attrs & ATTR_DIR )
return ( mode & ~ sbi - > options . fs_dmask ) | S_IFDIR ;
else
return ( mode & ~ sbi - > options . fs_fmask ) | S_IFREG ;
}
2008-11-06 23:53:46 +03:00
/* Return the FAT attribute byte for this inode */
2008-11-06 23:53:54 +03:00
static inline u8 fat_make_attrs ( struct inode * inode )
2008-11-06 23:53:46 +03:00
{
2008-11-06 23:53:54 +03:00
u8 attrs = MSDOS_I ( inode ) - > i_attrs ;
if ( S_ISDIR ( inode - > i_mode ) )
attrs | = ATTR_DIR ;
if ( fat_mode_can_hold_ro ( inode ) & & ! ( inode - > i_mode & S_IWUGO ) )
attrs | = ATTR_RO ;
return attrs ;
2008-11-06 23:53:46 +03:00
}
2008-11-06 23:53:54 +03:00
static inline void fat_save_attrs ( struct inode * inode , u8 attrs )
{
2008-11-06 23:53:54 +03:00
if ( fat_mode_can_hold_ro ( inode ) )
MSDOS_I ( inode ) - > i_attrs = attrs & ATTR_UNUSED ;
else
MSDOS_I ( inode ) - > i_attrs = attrs & ( ATTR_UNUSED | ATTR_RO ) ;
2008-11-06 23:53:54 +03:00
}
2008-11-06 23:53:46 +03:00
static inline unsigned char fat_checksum ( const __u8 * name )
{
unsigned char s = name [ 0 ] ;
s = ( s < < 7 ) + ( s > > 1 ) + name [ 1 ] ; s = ( s < < 7 ) + ( s > > 1 ) + name [ 2 ] ;
s = ( s < < 7 ) + ( s > > 1 ) + name [ 3 ] ; s = ( s < < 7 ) + ( s > > 1 ) + name [ 4 ] ;
s = ( s < < 7 ) + ( s > > 1 ) + name [ 5 ] ; s = ( s < < 7 ) + ( s > > 1 ) + name [ 6 ] ;
s = ( s < < 7 ) + ( s > > 1 ) + name [ 7 ] ; s = ( s < < 7 ) + ( s > > 1 ) + name [ 8 ] ;
s = ( s < < 7 ) + ( s > > 1 ) + name [ 9 ] ; s = ( s < < 7 ) + ( s > > 1 ) + name [ 10 ] ;
return s ;
}
static inline sector_t fat_clus_to_blknr ( struct msdos_sb_info * sbi , int clus )
{
return ( ( sector_t ) clus - FAT_START_ENT ) * sbi - > sec_per_clus
+ sbi - > data_start ;
}
static inline void fat16_towchar ( wchar_t * dst , const __u8 * src , size_t len )
{
# ifdef __BIG_ENDIAN
while ( len - - ) {
* dst + + = src [ 0 ] | ( src [ 1 ] < < 8 ) ;
src + = 2 ;
}
# else
memcpy ( dst , src , len * 2 ) ;
# endif
}
static inline void fatwchar_to16 ( __u8 * dst , const wchar_t * src , size_t len )
{
# ifdef __BIG_ENDIAN
while ( len - - ) {
dst [ 0 ] = * src & 0x00FF ;
dst [ 1 ] = ( * src & 0xFF00 ) > > 8 ;
dst + = 2 ;
src + + ;
}
# else
memcpy ( dst , src , len * 2 ) ;
# endif
}
/* fat/cache.c */
extern void fat_cache_inval_inode ( struct inode * inode ) ;
extern int fat_get_cluster ( struct inode * inode , int cluster ,
int * fclus , int * dclus ) ;
extern int fat_bmap ( struct inode * inode , sector_t sector , sector_t * phys ,
2008-11-06 23:53:57 +03:00
unsigned long * mapped_blocks , int create ) ;
2008-11-06 23:53:46 +03:00
/* fat/dir.c */
extern const struct file_operations fat_dir_operations ;
extern int fat_search_long ( struct inode * inode , const unsigned char * name ,
int name_len , struct fat_slot_info * sinfo ) ;
extern int fat_dir_empty ( struct inode * dir ) ;
extern int fat_subdirs ( struct inode * dir ) ;
extern int fat_scan ( struct inode * dir , const unsigned char * name ,
struct fat_slot_info * sinfo ) ;
extern int fat_get_dotdot_entry ( struct inode * dir , struct buffer_head * * bh ,
struct msdos_dir_entry * * de , loff_t * i_pos ) ;
extern int fat_alloc_new_dir ( struct inode * dir , struct timespec * ts ) ;
extern int fat_add_entries ( struct inode * dir , void * slots , int nr_slots ,
struct fat_slot_info * sinfo ) ;
extern int fat_remove_entries ( struct inode * dir , struct fat_slot_info * sinfo ) ;
/* fat/fatent.c */
struct fat_entry {
int entry ;
union {
u8 * ent12_p [ 2 ] ;
__le16 * ent16_p ;
__le32 * ent32_p ;
} u ;
int nr_bhs ;
struct buffer_head * bhs [ 2 ] ;
2009-06-07 21:44:36 +04:00
struct inode * fat_inode ;
2008-11-06 23:53:46 +03:00
} ;
static inline void fatent_init ( struct fat_entry * fatent )
{
fatent - > nr_bhs = 0 ;
fatent - > entry = 0 ;
fatent - > u . ent32_p = NULL ;
fatent - > bhs [ 0 ] = fatent - > bhs [ 1 ] = NULL ;
2009-06-07 21:44:36 +04:00
fatent - > fat_inode = NULL ;
2008-11-06 23:53:46 +03:00
}
static inline void fatent_set_entry ( struct fat_entry * fatent , int entry )
{
fatent - > entry = entry ;
fatent - > u . ent32_p = NULL ;
}
static inline void fatent_brelse ( struct fat_entry * fatent )
{
int i ;
fatent - > u . ent32_p = NULL ;
for ( i = 0 ; i < fatent - > nr_bhs ; i + + )
brelse ( fatent - > bhs [ i ] ) ;
fatent - > nr_bhs = 0 ;
fatent - > bhs [ 0 ] = fatent - > bhs [ 1 ] = NULL ;
2009-06-07 21:44:36 +04:00
fatent - > fat_inode = NULL ;
2008-11-06 23:53:46 +03:00
}
extern void fat_ent_access_init ( struct super_block * sb ) ;
extern int fat_ent_read ( struct inode * inode , struct fat_entry * fatent ,
int entry ) ;
extern int fat_ent_write ( struct inode * inode , struct fat_entry * fatent ,
int new , int wait ) ;
extern int fat_alloc_clusters ( struct inode * inode , int * cluster ,
int nr_cluster ) ;
extern int fat_free_clusters ( struct inode * inode , int cluster ) ;
extern int fat_count_free_clusters ( struct super_block * sb ) ;
/* fat/file.c */
extern int fat_generic_ioctl ( struct inode * inode , struct file * filp ,
unsigned int cmd , unsigned long arg ) ;
extern const struct file_operations fat_file_operations ;
extern const struct inode_operations fat_file_inode_operations ;
extern int fat_setattr ( struct dentry * dentry , struct iattr * attr ) ;
extern void fat_truncate ( struct inode * inode ) ;
extern int fat_getattr ( struct vfsmount * mnt , struct dentry * dentry ,
struct kstat * stat ) ;
2009-06-07 21:44:36 +04:00
extern int fat_file_fsync ( struct file * file , struct dentry * dentry ,
int datasync ) ;
2008-11-06 23:53:46 +03:00
/* fat/inode.c */
extern void fat_attach ( struct inode * inode , loff_t i_pos ) ;
extern void fat_detach ( struct inode * inode ) ;
extern struct inode * fat_iget ( struct super_block * sb , loff_t i_pos ) ;
extern struct inode * fat_build_inode ( struct super_block * sb ,
struct msdos_dir_entry * de , loff_t i_pos ) ;
extern int fat_sync_inode ( struct inode * inode ) ;
extern int fat_fill_super ( struct super_block * sb , void * data , int silent ,
const struct inode_operations * fs_dir_inode_ops , int isvfat ) ;
extern int fat_flush_inodes ( struct super_block * sb , struct inode * i1 ,
struct inode * i2 ) ;
/* fat/misc.c */
2009-06-03 21:34:22 +04:00
extern void fat_fs_error ( struct super_block * s , const char * fmt , . . . )
2008-11-06 23:53:56 +03:00
__attribute__ ( ( format ( printf , 2 , 3 ) ) ) __cold ;
2009-09-19 20:31:58 +04:00
extern int fat_clusters_flush ( struct super_block * sb ) ;
2008-11-06 23:53:46 +03:00
extern int fat_chain_add ( struct inode * inode , int new_dclus , int nr_cluster ) ;
2008-11-06 23:53:47 +03:00
extern void fat_time_fat2unix ( struct msdos_sb_info * sbi , struct timespec * ts ,
__le16 __time , __le16 __date , u8 time_cs ) ;
extern void fat_time_unix2fat ( struct msdos_sb_info * sbi , struct timespec * ts ,
__le16 * time , __le16 * date , u8 * time_cs ) ;
2008-11-06 23:53:46 +03:00
extern int fat_sync_bhs ( struct buffer_head * * bhs , int nr_bhs ) ;
int fat_cache_init ( void ) ;
void fat_cache_destroy ( void ) ;
2008-11-06 23:53:58 +03:00
/* helper for printk */
typedef unsigned long long llu ;
2008-11-06 23:53:46 +03:00
# endif /* !_FAT_H */