#include <stdio.h>
#include <string.h>
+#include "cache.h"
#include "core.h"
#include "disk.h"
#include "ext2_fs.h"
+#define MAX_OPEN_LG2 6
+#define MAX_OPEN (1 << MAX_OPEN_LG2)
+
+/*
+ * File structure, This holds the information for each currently open file
+ */
+struct open_file_t {
+ uint32_t file_bytesleft; /* Number of bytes left (0 = free) */
+ uint32_t file_sector; /* Next linear sector to read */
+ uint32_t file_in_sec; /* Sector where inode lives */
+ uint16_t file_in_off;
+ uint16_t file_mode;
+};
+
+extern char Files[MAX_OPEN * sizeof(struct open_file_t)];
+
+
+extern char ThisInode[128];
+struct ext2_inode *this_inode = ThisInode;
+
+extern uint16_t ClustByteShift, ClustShift;
+extern uint32_t SecPerClust, ClustSize, ClustMask;
+extern uint32_t PtrsPerBlock1, PtrsPerBlock2;
+uint32_t PtrsPerBlock3;
+
+int DescPerBlock, InodePerBlock;
+
+struct ext2_super_block *sb;
+
+
+
+/**
+ * allocate_file:
+ *
+ * Allocate a file structure
+ *
+ * @return: if successful return the file pointer, or return NULL
+ *
+ */
+struct open_file_t *allocate_file()
+{
+ struct open_file_t *file = (struct open_file_t *)Files;
+ int i = 0;
+
+ for (; i < MAX_OPEN; i ++) {
+ if (file->file_bytesleft == 0) /* found it */
+ return file;
+ file ++;
+ }
+
+ return NULL; /* not found */
+}
+
+
+/**
+ * get_group_desc:
+ *
+ * get the group's descriptor of group_num
+ *
+ * @param: group_num, the group number;
+ *
+ * @return: the pointer of the group's descriptor
+ *
+ */
+struct ext2_group_desc *get_group_desc(uint32_t group_num)
+{
+ block_t block_num;
+ uint32_t offset;
+ struct ext2_group_desc *desc;
+ struct cache_struct *cs;
+
+ block_num = group_num / DescPerBlock;
+ offset = group_num % DescPerBlock;
+
+ block_num += sb->s_first_data_block + 1;
+ cs = get_cache_block(block_num);
+
+ desc = (struct ext2_group_desc *)cs->data + offset;
+
+ return desc;
+}
+
+
+/**
+ * read_inode:
+ *
+ * read the right inode structure to _dst_.
+ *
+ * @param: inode_offset, the inode offset within a group;
+ * @prarm: dst, wher we will store the inode structure;
+ * @param: desc, the pointer to the group's descriptor
+ * @param: block, a pointer used for retruning the blk number for file structure
+ * @param: offset, same as block
+ *
+ */
+void read_inode(uint32_t inode_offset,
+ struct ext2_inode *dst, struct ext2_group_desc *desc,
+ block_t *block, uint32_t *offset)
+{
+ struct cache_struct *cs;
+ struct ext2_inode *inode;
+
+ *block = inode_offset / InodePerBlock + desc->bg_inode_table;
+ *offset = inode_offset % InodePerBlock;
+
+ cs = get_cache_block(*block);
+
+ /* well, in EXT4, the inode structure usually be 256 */
+ inode = (struct ext2_inode *)(cs->data + (*offset * (sb->s_inode_size)));
+ memcpy(dst, inode, EXT2_GOOD_OLD_INODE_SIZE);
+
+ /* for file structure */
+ *offset = (inode_offset * sb->s_inode_size) % ClustSize;
+}
+
+
+/**
+ * open_inode:
+ *
+ * open a file indicated by an inode number in INR
+ *
+ * @param : regs, regs->eax stores the inode number
+ * @return: a open_file_t structure pointer, stores in regs->esi
+ * file length in bytes, stores in regs->eax
+ * the first 128 bytes of the inode, stores in ThisInode
+ *
+ */
+void open_inode(com32sys_t *regs)
+{
+ uint32_t inr = regs->eax.l;
+ uint32_t file_len;
+
+ struct open_file_t *file;
+ struct ext2_group_desc *desc;
+
+ uint32_t inode_group, inode_offset;
+ block_t block_num;
+ uint32_t block_off;
+
+ file = allocate_file();
+ if (!file)
+ goto err;
+
+ file->file_sector = 0;
+
+ inr --;
+ inode_group = inr / sb->s_inodes_per_group;
+
+ /* get the group desc */
+ desc = get_group_desc(inode_group);
+
+ inode_offset = inr % sb->s_inodes_per_group;
+ read_inode(inode_offset, this_inode, desc, &block_num, &block_off);
+
+ /* Finally, we need to convet it to sector for now */
+ file->file_in_sec = (block_num<<ClustShift) + (block_off>>SECTOR_SHIFT);
+ file->file_in_off = block_off & (SECTOR_SIZE - 1);
+ file->file_mode = this_inode->i_mode;
+ file_len = file->file_bytesleft = this_inode->i_size;
+
+ if (file_len == 0)
+ goto err;
+
+ regs->esi.w[0] = file;
+ regs->eax.l = file_len;
+ return;
+
+ err:
+ regs->eax.l = 0;
+}
+
+
+
+struct ext4_extent_header *
+ext4_find_leaf (struct ext4_extent_header *eh, block_t block)
+{
+ struct ext4_extent_idx *index;
+ struct cache_struct *cs;
+ uint64_t blk;
+ int i;
+
+ while (1) {
+ if (eh->eh_magic != EXT4_EXT_MAGIC)
+ return NULL;
+
+ /* got it */
+ if (eh->eh_depth == 0)
+ return eh;
+
+ index = EXT4_FIRST_INDEX(eh);
+ for ( i = 0; i < eh->eh_entries; i++ ) {
+ if ( block < index[i].ei_block )
+ break;
+ }
+ if ( --i < 0 )
+ return NULL;
+
+ blk = index[i].ei_leaf_hi;
+ blk = (blk << 32) + index[i].ei_leaf_lo;
+
+ /* read the blk to memeory */
+ cs = get_cache_block(blk);
+ eh = (struct ext4_extent_header *)(cs->data);
+ }
+}
+
+/* handle the ext4 extents to get the phsical block number */
+uint64_t linsector_extent(block_t block, struct ext2_inode *inode)
+{
+ struct ext4_extent_header *leaf;
+ struct ext4_extent *ext;
+ int i;
+ uint64_t start;
+
+ leaf = ext4_find_leaf((struct ext4_extent_header*)inode->i_block,block);
+ if (! leaf) {
+ printf("ERROR, extent leaf not found\n");
+ return 0;
+ }
+
+ ext = EXT4_FIRST_EXTENT(leaf);
+ for ( i = 0; i < leaf->eh_entries; i++ ) {
+ if ( block < ext[i].ee_block)
+ break;
+ }
+ if ( --i < 0 ) {
+ printf("ERROR, not find the right block\n");
+ return 0;
+ }
+
+
+ /* got it */
+ block -= ext[i].ee_block;
+ if ( block >= ext[i].ee_len)
+ return 0;
+
+ start = ext[i].ee_start_hi;
+ start = (start << 32) + ext[i].ee_start_lo;
+
+ return start + block;
+}
+
+
+/**
+ * linsector_direct:
+ *
+ * @param: block, the block index
+ * @param: inode, the inode structure
+ *
+ * @return: the physic block number
+ */
+block_t linsector_direct(block_t block, struct ext2_inode *inode)
+{
+ struct cache_struct *cs;
+
+ /* direct blocks */
+ if (block < EXT2_NDIR_BLOCKS)
+ return inode->i_block[block];
+
+
+ /* indirect blocks */
+ block -= EXT2_NDIR_BLOCKS;
+ if (block < PtrsPerBlock1) {
+ block_t ind_block = inode->i_block[EXT2_IND_BLOCK];
+ cs = get_cache_block(ind_block);
+
+ return ((block_t *)cs->data)[block];
+ }
+
+ /* double indirect blocks */
+ block -= PtrsPerBlock1;
+ if (block < PtrsPerBlock2) {
+ block_t dou_block = inode->i_block[EXT2_DIND_BLOCK];
+ cs = get_cache_block(dou_block);
+
+ dou_block = ((block_t *)cs->data)[block / PtrsPerBlock1];
+ cs = get_cache_block(dou_block);
+
+ return ((block_t*)cs->data)[block % PtrsPerBlock1];
+ }
+
+ /* triple indirect block */
+ block -= PtrsPerBlock2;
+ if (block < PtrsPerBlock3) {
+ block_t tri_block = inode->i_block[EXT2_TIND_BLOCK];
+ cs = get_cache_block(tri_block);
+
+ tri_block = ((block_t *)cs->data)[block / PtrsPerBlock2];
+ cs = get_cache_block(tri_block);
+
+ tri_block = ((block_t *)cs->data)[block % PtrsPerBlock2];
+ cs = get_cache_block(tri_block);
+
+ return ((uint32_t*)cs->data)[block % PtrsPerBlock1];
+ }
+
+ /* File too big, can not handle */
+ printf("ERROR, file too big\n");
+ return 0;
+}
+
+
+/**
+ * linsector:
+ *
+ * Convert a linear sector index in a file to linear sector number
+ *
+ * well, alought this function converts a linear sector number to
+ * physic sector number, it uses block cache in the implemention.
+ *
+ * @param: lin_sector, the lineral sector index
+ *
+ * @return: physic sector number
+ */
+void linsector(com32sys_t *regs)
+{
+ sector_t lin_sector = regs->eax.l;
+ block_t block = lin_sector >> ClustShift;
+ struct ext2_inode *inode;
+
+ /* well, this is what I think the variable this_inode used for */
+ inode = this_inode;
+
+ if (inode->i_flags & EXT4_EXTENTS_FLAG)
+ block = linsector_extent(block, inode);
+ else
+ block = (uint32_t)linsector_direct(block, inode);
+
+ if (!block) {
+ printf("ERROR: something error happend at linsector..\n");
+ regs->eax.l = 0;
+ return;
+ }
+
+ /* finally convert it to sector */
+ regs->eax.l = ((block << ClustShift) + (lin_sector & ClustMask));
+}
+
+
/**
* init. the fs meta data, return the block size in eax
*/
void init_fs(com32sys_t *regs)
{
- extern uint16_t ClustByteShift, ClustShift;
- extern uint32_t SecPerClust, ClustSize, ClustMask;
- extern uint32_t PtrsPerBlock1, PtrsPerBlock2;
extern char SuperBlock[1024];
- struct ext2_super_block *sb;
/* read the super block */
read_sectors(SuperBlock, 2, 2);
ClustSize = 1 << ClustByteShift;
ClustShift = ClustByteShift - SECTOR_SHIFT;
- //DescPerBlock = ClustSize >> ext2_group_desc_lg2size;
- //InodePerBlock = ClustSize / sb->s_inode_size;
+ DescPerBlock = ClustSize >> ext2_group_desc_lg2size;
+ InodePerBlock = ClustSize / sb->s_inode_size;
SecPerClust = ClustSize >> SECTOR_SHIFT;
ClustMask = SecPerClust - 1;
PtrsPerBlock1 = 1 << ( ClustByteShift - 2 );
PtrsPerBlock2 = 1 << ( (ClustByteShift - 2) * 2);
- //PtrsPerBlock3 = 1 << ( (ClustByteShift - 2) * 3);
+ PtrsPerBlock3 = 1 << ( (ClustByteShift - 2) * 3);
- regs->eax.l = SECTOR_SHIFT;
+ regs->eax.l = ClustByteShift;
}
ClustByteShift resb 1 ; Shift count for bytes/cluster
alignb open_file_t_size
+ global Files
Files resb MAX_OPEN*open_file_t_size
;
jnz getlinsec_ext
ret
-;
-; allocate_file: Allocate a file structure
-;
-; If successful:
-; ZF set
-; BX = file pointer
-; In unsuccessful:
-; ZF clear
-;
-allocate_file:
- TRACER 'a'
- push cx
- mov bx,Files
- mov cx,MAX_OPEN
-.check: cmp dword [bx], byte 0
- je .found
- add bx,open_file_t_size ; ZF = 0
- loop .check
- ; ZF = 0 if we fell out of the loop
-.found: pop cx
- ret
-;
-; open_inode:
-; Open a file indicated by an inode number in EAX
-;
-; NOTE: This file considers finding a zero-length file an
-; error. This is so we don't have to deal with that special
-; case elsewhere in the program (most loops have the test
-; at the end).
-;
-; If successful:
-; ZF clear
-; SI = file pointer
-; EAX = file length in bytes
-; ThisInode = the first 128 bytes of the inode
-; If unsuccessful
-; ZF set
-;
-; Assumes CS == DS == ES.
-;
-open_inode.allocate_failure:
- xor eax,eax
- pop bx
- pop di
- ret
-
-open_inode:
- push di
- push bx
- call allocate_file
- jnz .allocate_failure
-
- push cx
- push gs
- ; First, get the appropriate inode group and index
- dec eax ; There is no inode 0
- xor edx,edx
- mov [bx+file_sector],edx
- div dword [SuperBlock+s_inodes_per_group]
- ; EAX = inode group; EDX = inode within group
- push edx
- ; Now, we need the block group descriptor.
- ; To get that, we first need the relevant descriptor block.
-
- shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table
- xor edx,edx
- div dword [ClustSize]
- ; eax = block #, edx = offset in block
- add eax,dword [SuperBlock+s_first_data_block]
- inc eax ; s_first_data_block+1
- mov cl,[ClustShift]
- shl eax,cl
- push edx
- shr edx,SECTOR_SHIFT
- add eax,edx
- pop edx
- and dx,SECTOR_SIZE-1
- pm_call get_cache_block ; Get the group descriptor
- add si,dx
- mov esi,[gs:si+bg_inode_table] ; Get inode table block #
- pop eax ; Get inode within group
- movzx edx, word [SuperBlock+s_inode_size]
- mul edx
- ; edx:eax = byte offset in inode table
- div dword [ClustSize]
- ; eax = block # versus inode table, edx = offset in block
- add eax,esi
- shl eax,cl ; Turn into sector
- push dx
- shr edx,SECTOR_SHIFT
- add eax,edx
- mov [bx+file_in_sec],eax
- pop dx
- and dx,SECTOR_SIZE-1
- mov [bx+file_in_off],dx
-
- pm_call get_cache_block
- add si,dx
- mov cx,EXT2_GOOD_OLD_INODE_SIZE >> 2
- mov di,ThisInode
- gs rep movsd
-
- mov ax,[ThisInode+i_mode]
- mov [bx+file_mode],ax
- mov eax,[ThisInode+i_size]
- mov [bx+file_bytesleft],eax
- mov si,bx
- and eax,eax ; ZF clear unless zero-length file
- pop gs
- pop cx
- pop bx
- pop di
- ret
section .bss16
alignb 4
+ global ThisInode
ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode
section .text16
.open:
push eax ; Save directory inode
- call open_inode
+ pm_call open_inode
jz .missing ; If error, done
mov cx,[si+file_mode]
.noreg: jmp short .noreg ; Nynorsk
-;
-; linsector: Convert a linear sector index in a file to a linear sector number
-; EAX -> linear sector number
-; DS:SI -> open_file_t
-;
-; Returns next sector number in EAX; CF on EOF (not an error!)
-;
-linsector:
- push gs
- push ebx
- push esi
- push edi
- push ecx
- push edx
- push ebp
-
- push eax ; Save sector index
- mov cl,[ClustShift]
- shr eax,cl ; Convert to block number
- push eax
- mov eax,[si+file_in_sec]
- mov bx,si
- pm_call get_cache_block ; Get inode
- add si,[bx+file_in_off] ; Get *our* inode
- pop eax
- lea ebx,[i_block+4*eax]
- cmp eax,EXT2_NDIR_BLOCKS
- jb .direct
- mov ebx,i_block+4*EXT2_IND_BLOCK
- sub eax,EXT2_NDIR_BLOCKS
- mov ebp,[PtrsPerBlock1]
- cmp eax,ebp
- jb .ind1
- mov ebx,i_block+4*EXT2_DIND_BLOCK
- sub eax,ebp
- mov ebp,[PtrsPerBlock2]
- cmp eax,ebp
- jb .ind2
- mov ebx,i_block+4*EXT2_TIND_BLOCK
- sub eax,ebp
-
-.ind3:
- ; Triple indirect; eax contains the block no
- ; with respect to the start of the tind area;
- ; ebx contains the pointer to the tind block.
- xor edx,edx
- div dword [PtrsPerBlock2]
- ; EAX = which dind block, EDX = pointer within dind block
- push ax
- shr eax,SECTOR_SHIFT-2
- mov ebp,[gs:si+bx]
- shl ebp,cl
- add eax,ebp
- pm_call get_cache_block
- pop bx
- and bx,(SECTOR_SIZE >> 2)-1
- shl bx,2
- mov eax,edx ; The ind2 code wants the remainder...
-
-.ind2:
- ; Double indirect; eax contains the block no
- ; with respect to the start of the dind area;
- ; ebx contains the pointer to the dind block.
- xor edx,edx
- div dword [PtrsPerBlock1]
- ; EAX = which ind block, EDX = pointer within ind block
- push ax
- shr eax,SECTOR_SHIFT-2
- mov ebp,[gs:si+bx]
- shl ebp,cl
- add eax,ebp
- pm_call get_cache_block
- pop bx
- and bx,(SECTOR_SIZE >> 2)-1
- shl bx,2
- mov eax,edx ; The int1 code wants the remainder...
-
-.ind1:
- ; Single indirect; eax contains the block no
- ; with respect to the start of the ind area;
- ; ebx contains the pointer to the ind block.
- push ax
- shr eax,SECTOR_SHIFT-2
- mov ebp,[gs:si+bx]
- shl ebp,cl
- add eax,ebp
- pm_call get_cache_block
- pop bx
- and bx,(SECTOR_SIZE >> 2)-1
- shl bx,2
-
-.direct:
- mov ebx,[gs:bx+si] ; Get the pointer
-
- pop eax ; Get the sector index again
- shl ebx,cl ; Convert block number to sector
- and eax,[ClustMask] ; Add offset within block
- add eax,ebx
-
- pop ebp
- pop edx
- pop ecx
- pop edi
- pop esi
- pop ebx
- pop gs
- ret
;
; getfssec: Get multiple sectors from a file
.getfragment:
mov eax,[si+file_sector] ; Current start index
mov edi,eax
- call linsector
+ pm_call linsector
push eax ; Fragment start sector
mov edx,eax
xor ebp,ebp ; Fragment sector count
inc edi ; Sector index
inc edx ; Linearly next sector
mov eax,edi
- call linsector
+ pm_call linsector
; jc .do_read
cmp edx,eax
je .getseccnt