/* * Copyright (C) 2013 Raphael S. Carvalho * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _UFS_H_ #define _UFS_H_ #include /* Sector addresses */ #define UFS1_SBLOCK_OFFSET 8192 #define UFS2_SBLOCK_OFFSET 65536 #define UFS2_SBLOCK2_OFFSET 262144 #define UFS1_ADDR_SHIFT 2 #define UFS2_ADDR_SHIFT 3 /* Super magic numbers */ #define UFS1_SUPER_MAGIC (0x011954) #define UFS2_SUPER_MAGIC (0x19540119) #define UFS_ROOT_INODE 2 #define UFS_DIRECT_BLOCKS 12 #define UFS_INDIRECT_BLOCK 1 #define UFS_DOUBLE_INDIRECT_BLOCK 1 #define UFS_TRIPLE_INDIRECT_BLOCK 1 /* Total number of block addr hold by inodes */ #define UFS_NBLOCKS 15 /* Blocks span 8 fragments */ #define FRAGMENTS_PER_BLK 8 /* UFS types */ typedef enum { NONE, UFS1, UFS2, UFS2_PIGGY, } ufs_t; /* * UFS1/UFS2 SUPERBLOCK structure * CG stands for Cylinder Group. * * Variables prepended with off store offsets relative to * base address of a Cylinder Group (CG). */ struct ufs_super_block { // supporting either ufs1 or ufs2 uint8_t unused[8]; /* Offset values */ uint32_t off_backup_sb; // Backup super block uint32_t off_group_desc; // Group Descriptor uint32_t off_inode_tbl; // Inode table uint32_t off_data_block; // First data block union { struct { /* Used for UFS1 */ uint32_t delta_value; // For calc staggering offset uint32_t cycle_mask; // Mask for staggering offset uint32_t last_written; // Last written time uint32_t nr_frags; // Number of frags in FS uint32_t storable_frags_nr; // Nr of frags that can store data } ufs1; uint8_t unused1[20]; }; uint32_t nr_cyl_groups; // Number of cylinder groups. uint32_t block_size; // Block size in bytes. uint32_t fragment_size; // Fragment size in bytes. uint8_t unused2[16]; uint32_t block_addr_mask; // to calculate the address uint32_t frag_addr_mask; uint32_t block_shift; // to calculate byte address uint32_t frag_shift; uint32_t nr_contiguous_blk; // max number of continuous blks to alloc uint32_t nr_blks_per_cg; // max number of blks per cylinder group uint32_t c_blk_frag_shift; // Bits to convert blk and frag address. uint32_t c_frag_sect_shift; // Bits to convert frag and sect address. uint32_t superblk_size; // Superblock size. uint8_t unused3[76]; uint32_t inodes_per_cg; // Inodes per cylinder group uint32_t frags_per_cg; // Fragments per cylinder group union { struct { /* Used for UFS2 */ uint8_t unused[888]; uint64_t nr_frags; // Number of fragments in FS uint8_t unused1[232]; } ufs2; uint8_t unused4[1128]; }; uint32_t maxlen_isymlink; // Max length of internal symlink uint32_t inodes_format; // Format of inodes uint8_t unused5[44]; uint32_t magic; // Magic value uint8_t pad[160]; // padding up to sector (512 bytes) boundary } __attribute__((__packed__)); /* * Info about UFS1/2 super block. */ struct ufs_sb_info { uint32_t blocks_per_cg; // Blocks per cylinder group uint32_t inodes_per_cg; // Inodes per cylinder group uint32_t inode_size; uint32_t inodes_per_block; // Inodes per block struct { /* UFS1 only! */ /* Values for calculating staggering offset */ uint32_t delta_value; uint32_t cycle_mask; } ufs1; uint32_t off_inode_tbl; // Inode table offset. uint32_t groups_count; // Number of groups in the fs uint32_t addr_shift; // 2 ^ addr_shift = size in bytes of default addr. uint32_t c_blk_frag_shift; // Convert blk/frag addr (vice-versa) uint32_t maxlen_isymlink; // Max length of internal symlink struct inode *(*ufs_iget_by_inr)(struct fs_info *, uint32_t); void (*ufs_read_blkaddrs)(struct inode *, char *); ufs_t fs_type; // { UFS1, UFS2, UFS2_PIGGY } }; /* * Get super block info struct */ static inline struct ufs_sb_info *UFS_SB(struct fs_info *fs) { return fs->fs_info; } /* * Convert frag addr to blk addr */ static inline block_t frag_to_blk(struct fs_info *fs, uint64_t frag) { return frag >> UFS_SB(fs)->c_blk_frag_shift; } /* * UFS1 inode structures */ struct ufs1_inode { uint16_t file_mode; uint16_t link_count; uint8_t unused[4]; uint64_t size; uint32_t a_time; // Access time uint32_t a_time_nanosec; uint32_t m_time; // Modified time uint32_t m_time_nanosec; uint32_t ch_time; // Change time uint32_t ch_time_nanosec; uint32_t direct_blk_ptr[12]; uint32_t indirect_blk_ptr; uint32_t double_indirect_blk_ptr; uint32_t triple_indirect_blk_ptr; uint32_t flags; // Status flags uint32_t blocks_held; // Blocks held uint32_t generation_nrb; // (NFS) uint32_t used_id; uint32_t group_id; uint8_t unused1[8]; } __attribute__((__packed__)); /* * UFS2 inode structures */ struct ufs2_inode { uint16_t file_mode; uint16_t link_count; uint32_t user_id; uint32_t group_id; uint32_t inode_blocksize; uint64_t size; uint64_t bytes_held; uint64_t a_time; // Access time uint64_t m_time; // Modified time uint64_t ch_time; // Change time uint64_t creat_time; // Creation time uint32_t a_time_nanosec; uint32_t m_time_nanosec; uint32_t ch_time_nanosec; uint32_t creat_time_nanosec; uint32_t generation_nrb; // (NFS) uint32_t kernel_flags; uint32_t flags; uint32_t ext_attr_size; // Extended attrib size. uint64_t ext_direct_blk_ptrs[2]; // Ext. attrib blk pointers. uint64_t direct_blk_ptr[12]; uint64_t indirect_blk_ptr; uint64_t double_indirect_blk_ptr; uint64_t triple_indirect_blk_ptr; uint8_t unused[24]; } __attribute__((__packed__)); #define PVT(p) ((struct ufs_inode_pvt *) p->pvt) struct ufs_inode_pvt { uint64_t direct_blk_ptr[12]; uint64_t indirect_blk_ptr; uint64_t double_indirect_blk_ptr; uint64_t triple_indirect_blk_ptr; }; struct ufs_dir_entry { uint32_t inode_value; uint16_t dir_entry_len; uint8_t file_type; uint8_t name_length; uint8_t name[1]; // Dir names are null terminated!!! } __attribute__((__packed__)); enum inode_type_flags { UFS_INO_FIFO = 0x1000, UFS_INO_CHARDEV = 0x2000, UFS_INO_DIRECTORY = 0x4000, UFS_INO_BLOCKDEV = 0x6000, UFS_INO_RFILE = 0x8000, UFS_INO_SYMLINK = 0xA000, UFS_INO_UNIXSOCKET = 0xC000, }; enum dir_type_flags { UFS_DTYPE_UNKNOWN = 0, UFS_DTYPE_FIFO = 1, UFS_DTYPE_CHARDEV = 2, UFS_DTYPE_DIR = 4, UFS_DTYPE_BLOCK = 6, UFS_DTYPE_RFILE = 8, UFS_DTYPE_SYMLINK = 10, UFS_DTYPE_SOCKET = 12, UFS_DTYPE_WHITEOUT = 14, }; /* Functions from bmap.c */ extern uint64_t ufs_bmap (struct inode *, block_t, size_t *); extern int ufs_next_extent(struct inode *, uint32_t); #define ufs_debug dprintf //extern void ufs_checking (struct fs_info *); #endif /* _UFS_H_ */