summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-12-28 17:38:48 -0800
committerH. Peter Anvin <hpa@zytor.com>2009-12-28 17:38:48 -0800
commit22d83c14f4d916e65ffee040468a7f944fdd30d7 (patch)
tree0396b906e78c6f21a55b20b932df95b36caa148f /core
parent078bd1b56a512c1dac52020d23382c1bdb37056d (diff)
parentb5839067e5fa11af7e76a6f6f87ef914ba9913d1 (diff)
downloadsyslinux-22d83c14f4d916e65ffee040468a7f944fdd30d7.tar.gz
Merge commit 'liu/master' into fsc
Resolved Conflicts: core/fs.c core/fs/ext2/ext2.c Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'core')
-rw-r--r--core/cache.c51
-rw-r--r--core/comboot.inc14
-rw-r--r--core/dir.c7
-rw-r--r--core/diskio.c56
-rw-r--r--core/diskstart.inc1
-rw-r--r--core/fs.c104
-rw-r--r--core/fs/ext2/bmap.c185
-rw-r--r--core/fs/ext2/ext2.c848
-rw-r--r--core/fs/ext2/ext2_fs.h69
-rw-r--r--core/fs/fat/fat.c1045
-rw-r--r--core/fs/fat/fat_fs.h33
-rw-r--r--core/fs/iso9660/iso9660.c745
-rw-r--r--core/fs/iso9660/iso9660_fs.h8
-rw-r--r--core/fs/pxe/dhcp_option.c40
-rw-r--r--core/fs/pxe/pxe.c3
-rw-r--r--core/include/core.h5
-rw-r--r--core/include/disk.h1
-rw-r--r--core/include/fs.h89
-rw-r--r--core/malloc.c216
19 files changed, 1827 insertions, 1693 deletions
diff --git a/core/cache.c b/core/cache.c
index c55f1603..415becff 100644
--- a/core/cache.c
+++ b/core/cache.c
@@ -1,24 +1,18 @@
-#include "core.h"
-#include "cache.h"
+/*
+ * core/cache.c: A simple LRU-based cache implementation.
+ *
+ */
+
#include <stdio.h>
#include <string.h>
+#include "core.h"
+#include "cache.h"
-/**
- * Each CachePtr contains:
- * - Block pointer
- * - LRU previous pointer
- * - LRU next pointer
- * - Block data buffer address
- *
- * The cache buffer are pointed to by a cache_head structure.
- */
-
-/**
- * cache_init:
- *
- * Initialize the cache data structres.
- * regs->eax.l stores the block size(in bits not bytes)
+/*
+ * Initialize the cache data structres. the _block_size_shift_ specify
+ * the block size, which is 512 byte for FAT fs of the current
+ * implementation since the block(cluster) size in FAT is a bit big.
*
*/
void cache_init(struct device *dev, int block_size_shift)
@@ -50,25 +44,10 @@ void cache_init(struct device *dev, int block_size_shift)
}
-/**
- * get_cache_block:
- *
+/*
* Check for a particular BLOCK in the block cache,
* and if it is already there, just do nothing and return;
- * otherwise load it and updata the relative cache
- * structre with data pointer.
- *
- * it's a test version for my start of merging extlinux into core.
- * and after I have figured out how to handle the relations between
- * rm and pm, c and asm, we call call it from C file, so no need
- * com32sys_t *regs any more.
- *
- * I just found that I was tring to do a stupid thing!
- * I haven't change the fs code to c, so for now the cache is based
- * on SECTOR SIZE but not block size. While we can fix it easily by
- * make the block size be the sector size.
- *
- * @return: the data stores at gs:si
+ * otherwise load it from disk and updata the LRU link.
*
*/
struct cache_struct* get_cache_block(struct device *dev, block_t block)
@@ -136,7 +115,7 @@ struct cache_struct* get_cache_block(struct device *dev, block_t block)
}
-/**
+/*
* Just print the sector, and according the LRU algorithm,
* Left most value is the most least secotr, and Right most
* value is the most Recent sector. I see it's a Left Right Used
@@ -148,7 +127,7 @@ void print_cache(struct device *dev)
struct cache_struct *cs = dev->cache_head;
for (; i < dev->cache_entries; i++) {
cs = cs->next;
- printf("%d(%p) ", cs->block, cs->data);
+ printf("%d(%p)\n", cs->block, cs->data);
}
printf("\n");
diff --git a/core/comboot.inc b/core/comboot.inc
index 72f642e4..25409595 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -899,7 +899,10 @@ comapi_getcwd:
;
; INT 22h AX=0020h Open directory
;
-%if IS_SYSLINUX
+%if IS_PXELINUX
+comapi_opendir equ comapi_err
+
+%else
comapi_opendir:
mov es,P_ES
mov si,P_SI
@@ -911,21 +914,20 @@ comapi_opendir:
mov P_EAX,eax
clc
ret
-%else
-comapi_opendir equ comapi_err
%endif
;
; INT 22h AX=0021h Read directory
;
-%if IS_SYSLINUX
+%if IS_PXELINUX
+comapi_readdir equ comapi_err
+
+%else
comapi_readdir:
mov esi,P_ESI ; The address of DIR structure
pm_call readdir
mov P_EAX,eax ; The address of newly read dirent structure
ret
-%else
-comapi_readdir equ comapi_err
%endif
;
diff --git a/core/dir.c b/core/dir.c
index 42400c91..37d92ed2 100644
--- a/core/dir.c
+++ b/core/dir.c
@@ -10,8 +10,11 @@ extern struct fs_info *this_fs;
* open dir, return the file structure pointer in _eax_, or NULL if failed
*/
void opendir(com32sys_t *regs)
-{
- this_fs->fs_ops->opendir(regs);
+{
+ char *src = MK_PTR(regs->es, regs->esi.w[0]);
+ char *dst = MK_PTR(regs->ds, regs->edi.w[0]);
+ strcpy(dst, src);
+ searchdir(regs);
regs->eax.l = (uint32_t)handle_to_file(regs->esi.w[0]);
}
diff --git a/core/diskio.c b/core/diskio.c
index c51f7225..911e4ddf 100644
--- a/core/diskio.c
+++ b/core/diskio.c
@@ -2,9 +2,9 @@
#include <string.h>
#include <stdbool.h>
#include <klibc/compiler.h>
-#include "core.h"
-#include "fs.h"
-#include "disk.h"
+#include <core.h>
+#include <fs.h>
+#include <disk.h>
#define RETRY_COUNT 6
@@ -17,7 +17,7 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf,
char *tptr;
size_t chunk, freeseg;
int sector_shift = disk->sector_shift;
- uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
+ uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
uint32_t t;
uint16_t c, h, s;
com32sys_t ireg, oreg;
@@ -227,25 +227,11 @@ static int ilog2(uint32_t num)
void getoneblk(struct disk *disk, char *buf, block_t block, int block_size)
{
- int sec_per_block = block_size >> SECTOR_SHIFT;
+ int sec_per_block = block_size / disk->sector_size;
disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0);
}
-static void dump_disk(struct disk *disk)
-{
- printf("drive number: 0x%x\n", disk->disk_number);
- printf("disk type: %s(%d)\n", disk->type ? "EDD" : "CHS", disk->type);
- printf("sector size: %d(%d)\n", disk->sector_size, disk->sector_shift);
- printf("h: %d\ts: %d\n", disk->h, disk->s);
- printf("offset: %d\n", disk->part_start);
- printf("%s\n", disk->rdwr_sectors == edd_rdwr_sectors ? "EDD_RDWR_SECTORS" :
- "CHS_RDWR_SECTORS");
- printf("--------------------------------\n");
- printf("disk->rdwr_sectors@: %p\n", disk->rdwr_sectors);
- printf("edd_rdwr_sectors @: %p\n", edd_rdwr_sectors);
- printf("chs_rdwr_sectors @: %p\n", chs_rdwr_sectors);
-}
struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
uint16_t bsHeads, uint16_t bsSecPerTrack)
@@ -305,9 +291,6 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
disk.part_start = part_start;
disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
-#if 0
- dump_disk(&disk);
-#endif
return &disk;
}
@@ -322,31 +305,8 @@ struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start,
dev.disk = disk_init(devno, cdrom, part_start, bsHeads, bsSecPerTrack);
- /* for now, isolinux doesn't use cache */
- if (!cdrom) {
- /*
- * FIX!! I can't use __lowmem here, 'cause it will cause the error:
- * "auxseg/lowmem region collides with xfer_buf_seg".
- *
- * static __lowmem char cache_buf[65536];
- */
- dev.cache_data = core_cache_buf;
- dev.cache_size = sizeof core_cache_buf;
- } else
- dev.cache_data = NULL;
-
+ dev.cache_data = core_cache_buf;
+ dev.cache_size = sizeof core_cache_buf;
+
return &dev;
}
-
-
-/* debug function */
-static void dump_dev(struct device *dev)
-{
- printf("device type:%s\n", dev->disk->type ? "EDD" : "CHS");
- printf("drive number: 0x%x\n", dev->disk->disk_number);
- printf("cache_data: %p\n", dev->cache_data);
- printf("cache_head: %p\n", dev->cache_head);
- printf("cache_block_size: %d\n", dev->cache_block_size);
- printf("cache_entries: %d\n", dev->cache_entries);
- printf("cache_size: %d\n", dev->cache_size);
-}
diff --git a/core/diskstart.inc b/core/diskstart.inc
index 4c4e8ee9..8bb4f78a 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -411,6 +411,7 @@ getlinsec_cbios:
;
; kaboom: write a message and bail out.
;
+ global kaboom
disk_error:
kaboom:
xor si,si
diff --git a/core/fs.c b/core/fs.c
index 81bda515..37808812 100644
--- a/core/fs.c
+++ b/core/fs.c
@@ -1,12 +1,13 @@
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
-#include "fs.h"
-#include "cache.h"
+#include <fs.h>
+#include <cache.h>
/* The currently mounted filesystem */
struct fs_info *this_fs = NULL;
static struct fs_info fs;
+struct inode *this_inode = NULL;
/* Actual file structures (we don't have malloc yet...) */
struct file files[MAX_OPEN];
@@ -20,7 +21,7 @@ static struct file *alloc_file(void)
struct file *file = files;
for (i = 0; i < MAX_OPEN; i++) {
- if (!file->open_file)
+ if (!file->fs)
return file;
file++;
}
@@ -38,7 +39,7 @@ static inline void free_file(struct file *file)
void _close_file(struct file *file)
{
- if (file->open_file)
+ if (file->fs)
file->fs->fs_ops->close_file(file);
free_file(file);
}
@@ -118,18 +119,25 @@ void getfssec(com32sys_t *regs)
void searchdir(com32sys_t *regs)
{
- char *filename = (char *)MK_PTR(regs->ds, regs->edi.w[0]);;
+ char *name = MK_PTR(regs->ds, regs->edi.w[0]);
+ struct inode *inode;
+ struct inode *parent;
struct file *file;
-
+ char part[256];
+ char *p;
+ int symlink_count = 6;
+
#if 0
- printf("filename: %s\n", filename);
+ printf("filename: %s\n", name);
#endif
- file = alloc_file();
-
- if (file) {
- file->fs = this_fs;
- file->fs->fs_ops->searchdir(filename, file);
+ if (!(file = alloc_file()))
+ goto err_no_close;
+ file->fs = this_fs;
+
+ /* if we have ->searchdir method, call it */
+ if (file->fs->fs_ops->searchdir) {
+ file->fs->fs_ops->searchdir(name, file);
if (file->open_file) {
regs->esi.w[0] = file_to_handle(file);
@@ -137,9 +145,68 @@ void searchdir(com32sys_t *regs)
regs->eflags.l &= ~EFLAGS_ZF;
return;
}
+
+ goto err;
+ }
+
+
+ /* else, try the generic-path-lookup method */
+ if (*name == '/') {
+ inode = this_fs->fs_ops->iget_root();
+ while(*name == '/')
+ name++;
+ } else {
+ inode = this_inode;
}
+ parent = inode;
- /* failure... */
+ while (*name) {
+ p = part;
+ while(*name && *name != '/')
+ *p++ = *name++;
+ *p = '\0';
+ inode = this_fs->fs_ops->iget(part, parent);
+ if (!inode)
+ goto err;
+ if (inode->mode == I_SYMLINK) {
+ if (!this_fs->fs_ops->follow_symlink ||
+ --symlink_count == 0 || /* limit check */
+ inode->size >= BLOCK_SIZE(this_fs))
+ goto err;
+ name = this_fs->fs_ops->follow_symlink(inode, name);
+ free_inode(inode);
+ continue;
+ }
+
+ /*
+ * For the relative path searching used in FAT and ISO fs.
+ */
+ if ((this_fs->fs_ops->fs_flags & FS_THISIND) && (this_inode != parent)){
+ if (this_inode)
+ free_inode(this_inode);
+ this_inode = parent;
+ }
+
+ if (parent != this_inode)
+ free_inode(parent);
+ parent = inode;
+ if (! *name)
+ break;
+ while(*name == '/')
+ name++;
+ }
+
+ file->inode = inode;
+ file->offset = 0;
+
+ regs->esi.w[0] = file_to_handle(file);
+ regs->eax.l = inode->size;
+ regs->eflags.l &= ~EFLAGS_ZF;
+ return;
+
+err:
+ _close_file(file);
+err_no_close:
regs->esi.w[0] = 0;
regs->eax.l = 0;
regs->eflags.l |= EFLAGS_ZF;
@@ -158,10 +225,12 @@ void close_file(com32sys_t *regs)
/*
* it will do:
+ * initialize the memory management function;
* set up the vfs fs structure;
* initialize the device structure;
* invoke the fs-specific init function;
- * finally, initialize the cache
+ * initialize the cache if we need one;
+ * finally, get the current inode for relative path looking.
*
*/
void fs_init(com32sys_t *regs)
@@ -176,6 +245,9 @@ void fs_init(com32sys_t *regs)
/* ops is a ptr list for several fs_ops */
const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l;
+ /* Initialize malloc() */
+ mem_init();
+
while ((blk_shift < 0) && *ops) {
/* set up the fs stucture */
fs.fs_ops = *ops;
@@ -202,7 +274,11 @@ void fs_init(com32sys_t *regs)
;
}
this_fs = &fs;
+
/* initialize the cache */
if (fs.fs_dev && fs.fs_dev->cache_data)
cache_init(fs.fs_dev, blk_shift);
+
+ if (fs.fs_ops->iget_current)
+ this_inode = fs.fs_ops->iget_current();
}
diff --git a/core/fs/ext2/bmap.c b/core/fs/ext2/bmap.c
new file mode 100644
index 00000000..e38bcd2c
--- /dev/null
+++ b/core/fs/ext2/bmap.c
@@ -0,0 +1,185 @@
+/*
+ * The logical block -> physical block routine.
+ *
+ * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file
+ * may be redistributed under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <fs.h>
+#include <disk.h>
+#include <cache.h>
+#include "ext2_fs.h"
+
+
+static struct ext4_extent_header *
+ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block)
+{
+ struct ext4_extent_idx *index;
+ struct cache_struct *cs;
+ block_t blk;
+ int i;
+
+ while (1) {
+ if (eh->eh_magic != EXT4_EXT_MAGIC)
+ return NULL;
+ if (eh->eh_depth == 0)
+ return eh;
+
+ index = EXT4_FIRST_INDEX(eh);
+ for (i = 0; i < (int)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;
+ cs = get_cache_block(fs->fs_dev, blk);
+ eh = (struct ext4_extent_header *)cs->data;
+ }
+}
+
+/* handle the ext4 extents to get the phsical block number */
+static uint64_t bmap_extent(struct fs_info *fs,
+ struct inode *inode,
+ uint32_t block)
+{
+ struct ext4_extent_header *leaf;
+ struct ext4_extent *ext;
+ int i;
+ block_t start;
+
+ leaf = ext4_find_leaf(fs, (struct ext4_extent_header *)inode->data, 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;
+}
+
+
+/*
+ * handle the traditional block map, like indirect, double indirect
+ * and triple indirect
+ */
+static unsigned int bmap_traditional(struct fs_info *fs,
+ struct inode *inode,
+ uint32_t block)
+{
+ int addr_per_block = BLOCK_SIZE(fs) >> 2;
+ uint32_t direct_blocks = EXT2_NDIR_BLOCKS,
+ indirect_blocks = addr_per_block,
+ double_blocks = addr_per_block * addr_per_block,
+ triple_blocks = double_blocks * addr_per_block;
+ struct cache_struct *cs;
+
+ /* direct blocks */
+ if (block < direct_blocks)
+ return inode->data[block];
+
+ /* indirect blocks */
+ block -= direct_blocks;
+ if (block < indirect_blocks) {
+ block_t ind_block = inode->data[EXT2_IND_BLOCK];
+
+ if (!ind_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, ind_block);
+
+ return ((uint32_t *)cs->data)[block];
+ }
+
+
+ /* double indirect blocks */
+ block -= indirect_blocks;
+ if (block < double_blocks) {
+ block_t dou_block = inode->data[EXT2_DIND_BLOCK];
+
+ if (!dou_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, dou_block);
+
+ dou_block = ((uint32_t *)cs->data)[block / indirect_blocks];
+ if (!dou_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, dou_block);
+
+ return ((uint32_t *)cs->data)[block % addr_per_block];
+ }
+
+
+ /* triple indirect block */
+ block -= double_blocks;
+ if (block < triple_blocks) {
+ block_t tri_block = inode->data[EXT2_TIND_BLOCK];
+
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ tri_block = ((uint32_t *)cs->data)[block / double_blocks];
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ tri_block = (block / addr_per_block) % addr_per_block;
+ tri_block = ((uint32_t *)cs->data)[tri_block];
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ return ((uint32_t *)cs->data)[block % addr_per_block];
+ }
+
+
+ /* File too big, can not handle */
+ printf("ERROR, file too big\n");
+ return 0;
+}
+
+
+/**
+ * Map the logical block to physic block where the file data stores.
+ * In EXT4, there are two ways to handle the map process, extents and indirect.
+ * EXT4 uses a inode flag to mark extent file and indirect block file.
+ *
+ * @fs: the fs_info structure.
+ * @inode: the inode structure.
+ * @block: the logical blcok needed to be maped.
+ * @retrun: the physic block number.
+ *
+ */
+block_t bmap(struct fs_info *fs, struct inode * inode, int block)
+{
+ block_t ret;
+
+ if (block < 0)
+ return 0;
+
+ if (inode->flags & EXT4_EXTENTS_FLAG)
+ ret = bmap_extent(fs, inode, block);
+ else
+ ret = bmap_traditional(fs, inode, block);
+
+ return ret;
+}
diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c
index dde5571e..9d4d9ec5 100644
--- a/core/fs/ext2/ext2.c
+++ b/core/fs/ext2/ext2.c
@@ -1,41 +1,17 @@
#include <stdio.h>
#include <string.h>
+#include <sys/dirent.h>
#include <cache.h>
#include <core.h>
#include <disk.h>
#include <fs.h>
#include "ext2_fs.h"
-#define MAX_SYMLINKS 64
-#define SYMLINK_SECTORS 2
-static char SymlinkBuf[SYMLINK_SECTORS * SECTOR_SIZE + 64];
-
-/*
- * 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 */
- sector_t file_in_sec; /* Sector where inode lives */
- uint16_t file_in_off;
- uint16_t file_mode;
- uint32_t pad[3]; /* pad to 2^5 == 0x20 bytes */
-};
-static struct open_file_t Files[MAX_OPEN];
-
-static struct ext2_inode this_inode;
-static struct ext2_super_block sb;
-
-static uint16_t ClustByteShift, ClustShift;
-static uint32_t SecPerClust, ClustSize, ClustMask;
-static uint32_t PtrsPerBlock1, PtrsPerBlock2, PtrsPerBlock3;
-static int DescPerBlock, InodePerBlock;
-
/*
* just like the function strcpy(), except it returns non-zero if overflow.
*
*/
-static int strecpy(char *dst, char *src, char *end)
+static int strecpy(char *dst, const char *src, char *end)
{
while (*src != '\0')
*dst++ = *src++;
@@ -47,278 +23,34 @@ static int strecpy(char *dst, char *src, char *end)
return 0;
}
-
-/*
- * Allocate a file structure, if successful return the file pointer, or NULL.
- *
- */
-static struct open_file_t *allocate_file(void)
-{
- struct open_file_t *file = Files;
- int i;
-
- for (i = 0; i < MAX_OPEN; i++) {
- if (file->file_bytesleft == 0) /* found it */
- return file;
- file++;
- }
-
- return NULL; /* not found */
-}
-
-
-/**
- * ext2_close_file:
- *
- * Deallocates a file structure point by FILE
- *
- * @param: file, the file structure we want deallocate
- *
- */
-static inline void close_pvt(struct open_file_t *of)
-{
- of->file_bytesleft = 0;
-}
-
static void ext2_close_file(struct file *file)
{
- close_pvt(file->open_file);
+ if (file->inode) {
+ file->offset = 0;
+ free_inode(file->inode);
+ }
}
-/**
+/*
* get the group's descriptor of group_num
- *
- * @param: group_num, the group number;
- *
- * @return: the pointer of the group's descriptor
- *
- */
-static struct ext2_group_desc *
-get_group_desc(struct fs_info *fs, 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(fs->fs_dev, block_num);
- desc = (struct ext2_group_desc *)cs->data + offset;
-
- return desc;
-}
-
-
-/**
- * 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
- *
*/
-static void read_inode(struct fs_info *fs, uint32_t inode_offset,
- struct ext2_inode *dst, struct ext2_group_desc *desc,
- block_t *block, uint32_t *offset)
+struct ext2_group_desc * ext2_get_group_desc(uint32_t group_num)
{
- struct cache_struct *cs;
- struct ext2_inode *inode;
-
- *block = inode_offset / InodePerBlock + desc->bg_inode_table;
- *offset = inode_offset % InodePerBlock;
-
- cs = get_cache_block(fs->fs_dev, *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;
+ struct ext2_sb_info *sbi = EXT2_SB(this_fs);
+
+ if (group_num >= sbi->s_groups_count) {
+ printf ("ext2_get_group_desc"
+ "block_group >= groups_count - "
+ "block_group = %d, groups_count = %d",
+ group_num, sbi->s_groups_count);
+
+ return NULL;
+ }
+
+ return sbi->s_group_desc[group_num];
}
-/**
- * open a file indicated by an inode number in INR
- *
- * @param : inr, the inode number
- * @return: a open_file_t structure pointer
- * file length in bytes
- * the first 128 bytes of the inode, stores in ThisInode
- *
- */
-static struct open_file_t *
-open_inode(struct fs_info *fs, uint32_t inr, 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)
- return NULL;
-
- file->file_sector = 0;
-
- inr --;
- inode_group = inr / sb.s_inodes_per_group;
-
- /* get the group desc */
- desc = get_group_desc(fs, inode_group);
-
- inode_offset = inr % sb.s_inodes_per_group;
- read_inode(fs, 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)
- return NULL;
-
- return file;
-}
-
-
-
-static struct ext4_extent_header *
-ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block)
-{
- struct ext4_extent_idx *index;
- struct cache_struct *cs;
- block_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(fs->fs_dev, blk);
- eh = (struct ext4_extent_header *)(cs->data);
- }
-}
-
-/* handle the ext4 extents to get the phsical block number */
-static block_t linsector_extent(struct fs_info *fs, block_t block,
- struct ext2_inode *inode)
-{
- struct ext4_extent_header *leaf;
- struct ext4_extent *ext;
- int i;
- block_t start;
-
- leaf = ext4_find_leaf(fs, (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
- */
-static block_t linsector_direct(struct fs_info *fs, uint32_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(fs->fs_dev, ind_block);
-
- return ((uint32_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(fs->fs_dev, dou_block);
-
- dou_block = ((uint32_t *)cs->data)[block / PtrsPerBlock1];
- cs = get_cache_block(fs->fs_dev, dou_block);
-
- return ((uint32_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(fs->fs_dev, tri_block);
-
- tri_block = ((uint32_t *)cs->data)[block / PtrsPerBlock2];
- cs = get_cache_block(fs->fs_dev, tri_block);
-
- tri_block = ((uint32_t *)cs->data)[block % PtrsPerBlock2];
- cs = get_cache_block(fs->fs_dev, tri_block);
-
- return ((uint32_t*)cs->data)[block % PtrsPerBlock1];
- }
-
- /* File too big, can not handle */
- printf("ERROR, file too big\n");
- return 0;
-}
-
/**
* linsector:
@@ -332,52 +64,17 @@ static block_t linsector_direct(struct fs_info *fs, uint32_t block, struct ext2_
*
* @return: physic sector number
*/
-static sector_t linsector(struct fs_info *fs, uint32_t lin_sector)
+static sector_t linsector(struct fs_info *fs,
+ struct inode *inode,
+ uint32_t lin_sector)
{
- uint32_t block = lin_sector >> ClustShift;
- block_t ret;
- 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)
- ret = linsector_extent(fs, block, inode);
- else
- ret = linsector_direct(fs, block, inode);
+ int blk_bits = fs->block_shift - fs->sector_shift;
+ block_t block = bmap(fs, inode, lin_sector >> blk_bits);
- if (!ret) {
- printf("ERROR: something error happend at linsector..\n");
- return 0;
- }
-
- /* finally convert it to sector */
- return ((ret << ClustShift) + (lin_sector & ClustMask));
-}
-
-
-/*
- * NOTE! unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
- *
- * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller.
- */
-static inline int ext2_match_entry (const char * const name,
- struct ext2_dir_entry * de)
-{
- if (!de->d_inode)
- return 0;
- return !strncmp(name, de->d_name, de->d_name_len);
+ return (block << blk_bits) + (lin_sector & ((1 << blk_bits) - 1));
}
-/*
- * p is at least 6 bytes before the end of page
- */
-static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
-{
- return (struct ext2_dir_entry *)((char*)p + p->d_rec_len);
-}
-
/**
* getlinsec_ext:
*
@@ -387,15 +84,16 @@ static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
*
*/
static void getlinsec_ext(struct fs_info *fs, char *buf,
- sector_t sector, int sector_cnt)
+ sector_t sector, int sector_cnt)
{
int ext_cnt = 0;
+ int sec_per_block = 1 << (fs->block_shift - fs->sector_shift);
struct disk *disk = fs->fs_dev->disk;
- if (sector < SecPerClust) {
- ext_cnt = SecPerClust - sector;
- memset(buf, 0, ext_cnt << SECTOR_SHIFT);
- buf += ext_cnt << SECTOR_SHIFT;
+ if (sector < sec_per_block) {
+ ext_cnt = sec_per_block - sector;
+ memset(buf, 0, ext_cnt << fs->sector_shift);
+ buf += ext_cnt << fs->sector_shift;
}
sector += ext_cnt;
@@ -403,9 +101,7 @@ static void getlinsec_ext(struct fs_info *fs, char *buf,
disk->rdwr_sectors(disk, buf, sector, sector_cnt, 0);
}
-/**
- * getfssec:
- *
+/*
* Get multiple sectors from a file
*
* Alought we have made the buffer data based on block size,
@@ -413,35 +109,27 @@ static void getlinsec_ext(struct fs_info *fs, char *buf,
* sectors (then can be multiple blocks) is what the function
* do. So, let it be based on sectors.
*
- * This function can be called from C function, and either from
- * ASM function.
- *
- * @param: ES:BX(of regs), the buffer to store data
- * @param: DS:SI(of regs), the pointer to open_file_t
- * @param: CX(of regs), number of sectors to read
- *
- * @return: ECX(of regs), number of bytes read
- *
*/
-static uint32_t ext2_getfssec(struct file *gfile, char *buf,
+static uint32_t ext2_getfssec(struct file *file, char *buf,
int sectors, bool *have_more)
{
+ struct inode *inode = file->inode;
+ struct fs_info *fs = file->fs;
int sector_left, next_sector, sector_idx;
int frag_start, con_sec_cnt;
- int bytes_read = sectors << SECTOR_SHIFT;
- struct open_file_t *file = gfile->open_file;
- struct fs_info *fs = gfile->fs;
+ int bytes_read = sectors << fs->sector_shift;
+ uint32_t bytesleft = inode->size - file->offset;
- sector_left = (file->file_bytesleft + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
+ sector_left = (bytesleft + SECTOR_SIZE(fs) - 1) >> fs->sector_shift;
if (sectors > sector_left)
sectors = sector_left;
+ sector_idx = file->offset >> fs->sector_shift;
while (sectors) {
/*
* get the frament
*/
- sector_idx = file->file_sector;
- next_sector = frag_start = linsector(fs, sector_idx);
+ next_sector = frag_start = linsector(fs, inode, sector_idx);
con_sec_cnt = 0;
/* get the consective sectors count */
@@ -457,226 +145,246 @@ static uint32_t ext2_getfssec(struct file *gfile, char *buf,
sector_idx ++;
next_sector ++;
- } while (next_sector == linsector(fs, sector_idx));
+ } while (next_sector == linsector(fs, inode, sector_idx));
-#if 0
+#if 0
printf("You are reading data stored at sector --0x%x--0x%x\n",
frag_start, frag_start + con_sec_cnt -1);
#endif
getlinsec_ext(fs, buf, frag_start, con_sec_cnt);
- buf += con_sec_cnt << 9;
- file->file_sector += con_sec_cnt; /* next sector index */
+ buf += con_sec_cnt << fs->sector_shift;
} while(sectors);
- if (bytes_read >= file->file_bytesleft) {
- bytes_read = file->file_bytesleft;
+ if (bytes_read >= bytesleft) {
+ bytes_read = bytesleft;
*have_more = 0;
} else {
*have_more = 1;
}
- file->file_bytesleft -= bytes_read;
-
+ file->offset += bytes_read;
+
return bytes_read;
}
-
+/*
+ * Unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
+ */
+static inline int ext2_match_entry (const char * const name,
+ struct ext2_dir_entry * de)
+{
+ if (!de->d_inode)
+ return 0;
+ if (strlen(name) != de->d_name_len)
+ return 0;
+ return !strncmp(name, de->d_name, de->d_name_len);
+}
-/**
- * find_dir_entry:
- *
- * find a dir entry, if find return it or return NULL
- *
+
+/*
+ * p is at least 6 bytes before the end of page
*/
-static struct ext2_dir_entry*
-find_dir_entry(struct fs_info *fs, struct open_file_t *file, char *filename)
+static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
{
- bool have_more;
- char *EndBlock = trackbuf + (SecPerClust << SECTOR_SHIFT);;
- struct ext2_dir_entry *de;
- struct file xfile;
+ return (struct ext2_dir_entry *)((char*)p + p->d_rec_len);
+}
- /* Fake out a VFS file structure */
- xfile.fs = fs;
- xfile.open_file = file;
+/*
+ * find a dir entry, return it if found, or return NULL.
+ */
+static struct ext2_dir_entry *
+ext2_find_entry(struct fs_info *fs, struct inode *inode, char *dname)
+{
+ int index = 0;
+ block_t block;
+ uint32_t i = 0;
+ struct ext2_dir_entry *de;
+ struct cache_struct *cs;
- /* read a clust at a time */
- ext2_getfssec(&xfile, trackbuf, SecPerClust, &have_more);
- de = (struct ext2_dir_entry *)trackbuf;
+ if (!(block = bmap(fs, inode, index++)))
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, block);
+ de = (struct ext2_dir_entry *)cs->data;
+
+ while(i < (int)inode->size) {
+ if (ext2_match_entry(dname, de))
+ return de;
+ i += de->d_rec_len;
+ if (i >= (int)inode->size)
+ break;
+ if ((char *)de >= (char *)cs->data + BLOCK_SIZE(fs)) {
+ if (!(block = bmap(fs, inode, index++)))
+ break;
+ cs = get_cache_block(fs->fs_dev, block);
+ de = (struct ext2_dir_entry *)cs->data;
+ continue;
+ }
+
+ de = ext2_next_entry(de);
+ }
- while (1) {
- if ((char *)de >= (char *)EndBlock) {
- if (!have_more)
- return NULL;
- ext2_getfssec(&xfile, trackbuf, SecPerClust, &have_more);
- de = (struct ext2_dir_entry *)trackbuf;
- }
-
- /* Zero inode == void entry */
- if (de->d_inode == 0) {
- de = ext2_next_entry(de);
- continue;
- }
-
- if (ext2_match_entry (filename, de)) {
- filename += de->d_name_len;
- if ((*filename == 0) || (*filename == '/'))
- return de; /* got it */
-
- /* not match, restore the filename then try next */
- filename -= de->d_name_len;
- }
-
- de = ext2_next_entry(de);
- }
+ return NULL;
}
-
-static char *do_symlink(struct fs_info *fs, struct open_file_t *file,
- uint32_t file_len, char *filename)
+static struct ext2_inode * get_inode(int inr)
{
- int flag;
- bool have_more;
-
- char *SymlinkTmpBuf = trackbuf;
- char *lnk_end;
- char *SymlinkTmpBufEnd = trackbuf + SYMLINK_SECTORS * SECTOR_SIZE+64;
- struct file xfile;
- xfile.fs = fs;
- xfile.open_file = file;
-
- flag = this_inode.i_file_acl ? SecPerClust : 0;
- if (this_inode.i_blocks == flag) {
- /* fast symlink */
- close_pvt(file); /* we've got all we need */
- memcpy(SymlinkTmpBuf, this_inode.i_block, file_len);
- lnk_end = SymlinkTmpBuf + file_len;
-
- } else {
- /* slow symlink */
- ext2_getfssec(&xfile, SymlinkTmpBuf, SYMLINK_SECTORS, &have_more);
- lnk_end = SymlinkTmpBuf + file_len;
- }
+ struct ext2_group_desc *desc;
+ struct cache_struct *cs;
+ uint32_t inode_group, inode_offset;
+ uint32_t block_num, block_off;
- if (*filename != 0)
- *lnk_end++ = '/';
+ inr--;
+ inode_group = inr / EXT2_INODES_PER_GROUP(this_fs);
+ inode_offset = inr % EXT2_INODES_PER_GROUP(this_fs);
+ desc = ext2_get_group_desc (inode_group);
+ if (!desc)
+ return NULL;
- if (strecpy(lnk_end, filename, SymlinkTmpBufEnd))
- return NULL; /* buffer overflow */
+ block_num = desc->bg_inode_table +
+ inode_offset / EXT2_INODES_PER_BLOCK(this_fs);
+ block_off = inode_offset % EXT2_INODES_PER_BLOCK(this_fs);
- /*
- * now copy it to the "real" buffer; we need to have
- * two buffers so we avoid overwriting the tail on
- * the next copy.
- */
- strcpy(SymlinkBuf, SymlinkTmpBuf);
+ cs = get_cache_block(this_fs->fs_dev, block_num);
- /* return the new path */
- return SymlinkBuf;
+ return cs->data + block_off * EXT2_SB(this_fs)->s_inode_size;
}
+static inline int get_inode_mode(int mode)
+{
+ mode >>= S_IFSHIFT;
+ if (mode == T_IFDIR)
+ mode = I_DIR;
+ else if (mode == T_IFLNK)
+ mode = I_SYMLINK;
+ else
+ mode = I_FILE; /* we treat others as FILE */
+ return mode;
+}
+static void fill_inode(struct inode *inode, struct ext2_inode *e_inode)
+{
+ inode->mode = get_inode_mode(e_inode->i_mode);
+ inode->size = e_inode->i_size;
+ inode->atime = e_inode->i_atime;
+ inode->ctime = e_inode->i_ctime;
+ inode->mtime = e_inode->i_mtime;
+ inode->dtime = e_inode->i_dtime;
+ inode->blocks = e_inode->i_blocks;
+ inode->flags = e_inode->i_flags;
+ inode->file_acl = e_inode->i_file_acl;
+
+ inode->data = malloc(EXT2_N_BLOCKS * sizeof(uint32_t *));
+ if (!inode->data) {
+ malloc_error("inode data filed");
+ return ;
+ }
+ memcpy(inode->data, e_inode->i_block, EXT2_N_BLOCKS * sizeof(uint32_t *));
+}
+static struct inode *ext2_iget_by_inr(uint32_t inr)
+{
+ struct ext2_inode *e_inode;
+ struct inode *inode;
+
+ e_inode = get_inode(inr);
+ if (!(inode = malloc(sizeof(*inode))))
+ return NULL;
+ fill_inode(inode, e_inode);
+ inode->ino = inr;
+
+ return inode;
+}
-/**
- * Search the root directory for a pre-mangle filename in FILENAME.
- *
- * @param: filename, the filename we want to search.
- *
- * @out : a open_file_t structure pointer, stores in file->open_file
- * @out : file lenght in bytes, stores in file->file_len
- *
- */
-static void ext2_searchdir(char *filename, struct file *file)
+static struct inode *ext2_iget_root()
+{
+ return ext2_iget_by_inr(EXT2_ROOT_INO);
+}
+
+static struct inode *ext2_iget_current()
{
extern int CurrentDir;
- struct open_file_t *open_file;
- struct ext2_dir_entry *de;
- uint8_t file_mode;
- uint8_t SymlinkCtr = MAX_SYMLINKS;
- uint32_t inr = CurrentDir;
- uint32_t ThisDir = CurrentDir;
- uint32_t file_len;
+ return ext2_iget_by_inr(CurrentDir);
+}
+
+static struct inode *ext2_iget(char *dname, struct inode *parent)
+{
+ struct ext2_dir_entry *de;
- begin_path:
- while (*filename == '/') { /* Absolute filename */
- inr = EXT2_ROOT_INO;
- filename ++;
- }
- open:
- if ((open_file = open_inode(file->fs, inr, &file_len)) == NULL)
- goto err_noclose;
+ de = ext2_find_entry(this_fs, parent, dname);
+ if (!de)
+ return NULL;
- file_mode = open_file->file_mode >> S_IFSHIFT;
+ return ext2_iget_by_inr(de->d_inode);
+}
+
+
+static char * ext2_follow_symlink(struct inode *inode, const char *name_left)
+{
+ int sec_per_block = 1 << (this_fs->block_shift - this_fs->sector_shift);
+ int fast_symlink;
+ char *symlink_buf;
+ char *p;
+ struct cache_struct *cs;
- /* It's a file */
- if (file_mode == T_IFREG) {
- if (*filename == '\0')
- goto done;
- else
- goto err;
- }
+ symlink_buf = malloc(BLOCK_SIZE(this_fs));
+ if (!symlink_buf) {
+ malloc_error("symlink buffer");
+ return NULL;
+ }
+ fast_symlink = (inode->file_acl ? sec_per_block : 0) == inode->blocks;
+ if (fast_symlink) {
+ memcpy(symlink_buf, inode->data, inode->size);
+ } else {
+ cs = get_cache_block(this_fs->fs_dev, *(uint32_t *)inode->data);
+ memcpy(symlink_buf, cs->data, inode->size);
+ }
+ p = symlink_buf + inode->size;
+ if (*name_left)
+ *p++ = '/';
+ if (strecpy(p, name_left, symlink_buf + BLOCK_SIZE(this_fs))) {
+ free(symlink_buf);
+ return NULL;
+ }
+ if(!(p = strdup(symlink_buf)))
+ return symlink_buf;
- /* It's a directory */
- if (file_mode == T_IFDIR) {
- ThisDir = inr;
-
- if (*filename == 0)
- goto err;
- while (*filename == '/')
- filename ++;
-
- de = find_dir_entry(file->fs, open_file, filename);
- if (!de)
- goto err;
-
- inr = de->d_inode;
- filename += de->d_name_len;
- close_pvt(open_file);
- goto open;
- }
+ free(symlink_buf);
+ return p;
+}
+
+/*
+ * Read one directory entry at a time
+ */
+static struct dirent * ext2_readdir(struct file *file)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ struct dirent *dirent;
+ struct ext2_dir_entry *de;
+ struct cache_struct *cs;
+ int index = file->offset >> fs->block_shift;
+ block_t block;
-
- /*
- * It's a symlink. We have to determine if it's a fast symlink
- * (data stored in the inode) or not (data stored as a regular
- * file.) Either which way, we start from the directory
- * which we just visited if relative, or from the root directory
- * if absolute, and append any remaining part of the path.
- */
- if (file_mode == T_IFLNK) {
- if (--SymlinkCtr==0 || file_len>=SYMLINK_SECTORS*SECTOR_SIZE)
- goto err; /* too many links or symlink too long */
-
- filename = do_symlink(file->fs, open_file, file_len, filename);
- if (!filename)
- goto err_noclose;/* buffer overflow */
-
- inr = ThisDir;
- goto begin_path; /* we got a new path, so search it again */
+ if (!(block = bmap(fs, inode, index)))
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, block);
+ de = (struct ext2_dir_entry *)(cs->data + (file->offset & (BLOCK_SIZE(fs) - 1)));
+
+ if (!(dirent = malloc(sizeof(*dirent)))) {
+ malloc_error("dirent structure in ext2_readdir");
+ return NULL;
}
+ dirent->d_ino = de->d_inode;
+ dirent->d_off = file->offset;
+ dirent->d_reclen = de->d_rec_len;
+ dirent->d_type = de->d_file_type;
+ memcpy(dirent->d_name, de->d_name, de->d_name_len);
+ dirent->d_name[de->d_name_len] = '\0';
- /* Otherwise, something bad ... */
- err:
- close_pvt(open_file);
- err_noclose:
- file_len = 0;
- open_file = NULL;
- done:
+ file->offset += de->d_rec_len; /* Update for next reading */
- file->file_len = file_len;
- file->open_file = (void*)open_file;
-
-#if 0
- if (open_file) {
- printf("file bytesleft: %d\n", open_file->file_bytesleft);
- printf("file sector : %d\n", open_file->file_sector);
- printf("file in sector: %d\n", open_file->file_in_sec);
- printf("file offsector: %d\n", open_file->file_in_off);
- }
-#endif
-
+ return dirent;
}
/* Load the config file, return 1 if failed, or 0 */
@@ -702,38 +410,86 @@ static int ext2_load_config(void)
static int ext2_fs_init(struct fs_info *fs)
{
struct disk *disk = fs->fs_dev->disk;
-
+ struct ext2_sb_info *sbi;
+ struct ext2_super_block sb;
+ int blk_bits;
+ int db_count;
+ int i;
+ int desc_block;
+ char *desc_buffer;
+
/* read the super block */
disk->rdwr_sectors(disk, &sb, 2, 2, 0);
/* check if it is ext2, since we also support btrfs now */
if (sb.s_magic != EXT2_SUPER_MAGIC)
return -1;
- ClustByteShift = sb.s_log_block_size + 10;
- ClustSize = 1 << ClustByteShift;
- ClustShift = ClustByteShift - SECTOR_SHIFT;
-
- DescPerBlock = ClustSize >> ext2_group_desc_lg2size;
- InodePerBlock = ClustSize / sb.s_inode_size;
-
- SecPerClust = ClustSize >> SECTOR_SHIFT;
- ClustMask = SecPerClust - 1;
+
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi) {
+ malloc_error("ext2_sb_info structure");
+ return -1;
+ }
+ fs->fs_info = sbi;
- PtrsPerBlock1 = 1 << (ClustByteShift - 2);
- PtrsPerBlock2 = 1 << ((ClustByteShift - 2) * 2);
- PtrsPerBlock3 = 1 << ((ClustByteShift - 2) * 3);
+ if (sb.s_magic != EXT2_SUPER_MAGIC) {
+ printf("ext2 mount error: it's not a EXT2/3/4 file system!\n");
+ return 0;
+ }
+
+ fs->sector_shift = disk->sector_shift;
+ fs->block_shift = sb.s_log_block_size + 10;
+
+ sbi->s_inodes_per_group = sb.s_inodes_per_group;
+ sbi->s_blocks_per_group = sb.s_blocks_per_group;
+ sbi->s_inodes_per_block = BLOCK_SIZE(fs) / sb.s_inode_size;
+ if (sb.s_desc_size < sizeof(struct ext2_group_desc))
+ sb.s_desc_size = sizeof(struct ext2_group_desc);
+ sbi->s_desc_per_block = BLOCK_SIZE(fs) / sb.s_desc_size;
+ sbi->s_groups_count = (sb.s_blocks_count - sb.s_first_data_block
+ + EXT2_BLOCKS_PER_GROUP(fs) - 1)
+ / EXT2_BLOCKS_PER_GROUP(fs);
+ db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(fs) - 1) /
+ EXT2_DESC_PER_BLOCK(fs);
+ sbi->s_inode_size = sb.s_inode_size;
+
+ /* read the descpritors */
+ desc_block = sb.s_first_data_block + 1;
+ desc_buffer = malloc(db_count * BLOCK_SIZE(fs));
+ if (!desc_buffer) {
+ malloc_error("desc_buffer");
+ return -1;
+ }
+ blk_bits = fs->block_shift - fs->sector_shift;
+ disk->rdwr_sectors(disk, desc_buffer, desc_block << blk_bits,
+ db_count << blk_bits, 0);
+ sbi->s_group_desc = malloc(sizeof(struct ext2_group_desc *)
+ * sbi->s_groups_count);
+ if (!sbi->s_group_desc) {
+ malloc_error("sbi->s_group_desc");
+ return -1;
+ }
+ for (i = 0; i < (int)sbi->s_groups_count; i++) {
+ sbi->s_group_desc[i] = (struct ext2_group_desc *)desc_buffer;
+ desc_buffer += sb.s_desc_size;
+ }
- return ClustByteShift;
+ return fs->block_shift;
}
const struct fs_ops ext2_fs_ops = {
.fs_name = "ext2",
- .fs_flags = 0,
+ .fs_flags = FS_USEMEM,
.fs_init = ext2_fs_init,
- .searchdir = ext2_searchdir,
+ .searchdir = NULL,
.getfssec = ext2_getfssec,
.close_file = ext2_close_file,
.mangle_name = generic_mangle_name,
.unmangle_name = generic_unmangle_name,
- .load_config = ext2_load_config
+ .load_config = ext2_load_config,
+ .iget_root = ext2_iget_root,
+ .iget_current = ext2_iget_current,
+ .iget = ext2_iget,
+ .follow_symlink = ext2_follow_symlink,
+ .readdir = ext2_readdir
};
diff --git a/core/fs/ext2/ext2_fs.h b/core/fs/ext2/ext2_fs.h
index d579eade..0249ee16 100644
--- a/core/fs/ext2/ext2_fs.h
+++ b/core/fs/ext2/ext2_fs.h
@@ -105,8 +105,37 @@ struct ext2_super_block {
uint32_t s_algorithm_usage_bitmap; /* For compression */
uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
uint8_t s_prealloc_dir_blocks;
- uint16_t s_padding1;
- uint32_t s_reserved[204]; /* Padding to the end of the block */
+ uint16_t s_reserved_gdt_blocks; /* Per group desc for online growth */
+ /*
+ * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
+ uint32_t s_journal_inum; /* inode number of journal file */
+ uint32_t s_journal_dev; /* device number of journal file */
+ uint32_t s_last_orphan; /* start of list of inodes to delete */
+ uint32_t s_hash_seed[4]; /* HTREE hash seed */
+ uint8_t s_def_hash_version; /* Default hash version to use */
+ uint8_t s_reserved_char_pad;
+ uint16_t s_desc_size; /* size of group descriptor */
+ uint32_t s_default_mount_opts;
+ uint32_t s_first_meta_bg; /* First metablock block group */
+ uint32_t s_mkfs_time; /* When the filesystem was created */
+ uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
+ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+ uint32_t s_blocks_count_hi; /* Blocks count */
+ uint32_t s_r_blocks_count_hi; /* Reserved blocks count */
+ uint32_t s_free_blocks_count_hi;/* Free blocks count */
+ uint16_t s_min_extra_isize; /* All inodes have at least # bytes */
+ uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */
+ uint32_t s_flags; /* Miscellaneous flags */
+ uint16_t s_raid_stride; /* RAID stride */
+ uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */
+ uint64_t s_mmp_block; /* Block for multi-mount protection */
+ uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
+ uint8_t s_log_groups_per_flex; /* FLEX_BG group size */
+ uint8_t s_reserved_char_pad2;
+ uint16_t s_reserved_pad;
+ uint32_t s_reserved[162]; /* Padding to the end of the block */
};
/*******************************************************************************
@@ -237,16 +266,40 @@ struct ext4_extent_header {
#define EXT4_FIRST_INDEX(header) ( (struct ext4_extent_idx *) (header + 1) )
+/*
+ * The ext2 super block information in memory
+ */
+struct ext2_sb_info {
+ uint32_t s_inodes_per_block;/* Number of inodes per block */
+ uint32_t s_inodes_per_group;/* Number of inodes in a group */
+ uint32_t s_blocks_per_group;/* Number of blocks in a group */
+ uint32_t s_desc_per_block; /* Number of group descriptors per block */
+ uint32_t s_groups_count; /* Number of groups in the fs */
+ int s_inode_size;
+
+ /*
+ * Here did not like Linux Kernel did; the group descriptor cache
+ * here is based on ext2_group_desc structure, instead of buffer
+ * head structure in Linux Kernel, where cache one block data.
+ */
+ struct ext2_group_desc ** s_group_desc;
+};
+static inline struct ext2_sb_info *EXT2_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+#define EXT2_BLOCKS_PER_GROUP(fs) (EXT2_SB(fs)->s_blocks_per_group)
+#define EXT2_INODES_PER_GROUP(fs) (EXT2_SB(fs)->s_inodes_per_group)
+#define EXT2_INODES_PER_BLOCK(fs) (EXT2_SB(fs)->s_inodes_per_block)
+#define EXT2_DESC_PER_BLOCK(fs) (EXT2_SB(fs)->s_desc_per_block)
-
-/* function declartion */
-/*******************************************************************************
-extern struct open_file_t * ext2_read(char *);
-extern int ext2_read(struct open_file_t *, char *, int);
-*******************************************************************************/
+/*
+ * functions
+ */
+block_t bmap(struct fs_info *, struct inode *, int);
#endif /* ext2_fs.h */
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index e7931b0f..d77fcb12 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -7,213 +7,153 @@
#include <fs.h>
#include "fat_fs.h"
-#define ROOT_DIR_WORD 0x002f
-/* file structure. This holds the information for each currently open file */
-struct open_file_t {
- sector_t file_sector; /* sector pointer (0 = structure free) */
- uint32_t file_bytesleft; /* number of bytes left */
- uint32_t file_left; /* number of sectors left */
-};
-
-static struct open_file_t Files[MAX_OPEN];
-
-extern uint8_t SecPerClust;
-
-/* the fat bpb data */
-static struct fat_bpb fat;
-static int FATType = 0;
-
-/* generic information about FAT fs */
-static sector_t FAT; /* Location of (first) FAT */
-static sector_t RootDirArea; /* Location of root directory area */
-static sector_t RootDir; /* Location of root directory proper */
-static sector_t DataArea; /* Location of data area */
-static uint32_t TotalSectors; /* Total number of sectors */
-static uint32_t ClustSize; /* Bytes/cluster */
-static uint32_t ClustMask; /* Sector/cluster - 1 */
-static uint8_t ClustShift; /* Shift count for sectors/cluster */
-static uint8_t ClustByteShift; /* Shift count for bytes/cluster */
-
-static int CurrentDir;
-static int PrevDir;
-
-/* used for long name entry */
-static char MangleBuf[12];
-static char entry_name[14];
-
-/* try with the biggest long name */
-static char long_name[0x40 * 13];
-static char *NameStart;
-static int NameLen;
-
-/*
- * Allocate a file structure, if successful return the file pointer, or NULL.
- *
- */
-static struct open_file_t *allocate_file(void)
-{
- struct open_file_t *file = Files;
- int i = 0;
-
- for (; i < MAX_OPEN; i ++) {
- if (file->file_sector == 0) /* found it */
- return file;
- file ++;
- }
-
- return NULL; /* not found */
-}
-
-
-/*
- * Allocate then fill a file structure for a directory starting in
- * sector SECTOR. if successful, return the pointer of filled file
- * structure, or return NULL.
- *
- */
-static struct open_file_t *alloc_fill_dir(sector_t sector)
+static struct inode * new_fat_inode(void)
{
- struct open_file_t *file;
+ struct inode *inode = malloc(sizeof(*inode));
+ if (!inode)
+ malloc_error("inode structure");
+ memset(inode, 0, sizeof(*inode));
- file = allocate_file();
- if (!file)
- return NULL;
+ /*
+ * We just need allocate one uint32_t data to store the
+ * first cluster number.
+ */
+ inode->data = malloc(sizeof(uint32_t));
+ if (!inode->data)
+ malloc_error("inode->data");
- file->file_sector = sector; /* current sector */
- file->file_bytesleft = 0; /* current offset */
- file->file_left = sector; /* beginning sector */
- return file;
+ return inode;
}
-/* Deallocates a file structure */
-static inline void close_pvt(struct open_file_t *of)
-{
- of->file_sector = 0;
-}
-
static void vfat_close_file(struct file *file)
{
- close_pvt(file->open_file);
+ if (file->inode) {
+ file->offset = 0;
+ free_inode(file->inode);
+ }
}
/*
- * check for a particular sector in the FAT cache.
- *
+ * Check for a particular sector in the FAT cache
*/
-static struct cache_struct *getfatsector(struct fs_info *fs, sector_t sector)
+static struct cache_struct * get_fat_sector(struct fs_info *fs, sector_t sector)
{
- return get_cache_block(fs->fs_dev, FAT + sector);
+ return get_cache_block(fs->fs_dev, FAT_SB(fs)->fat + sector);
}
-
-/**
- * Advance a cluster pointer in clust_num to the next cluster
- * pointer at in the FAT tables. return the next cluster number
- * if success, or return 0 if end of file.
- *
- */
-static uint32_t nextcluster(struct fs_info *fs, uint32_t clust_num)
+static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num)
{
uint32_t next_cluster;
sector_t fat_sector;
uint32_t offset;
int lo, hi;
struct cache_struct *cs;
-
- switch(FATType) {
+
+ switch(FAT_SB(fs)->fat_type) {
case FAT12:
- fat_sector = (clust_num + clust_num / 2) >> SECTOR_SHIFT;
- cs = getfatsector(fs, fat_sector);
- offset = (clust_num * 3 / 2) & (SECTOR_SIZE -1);
- if (offset == 0x1ff) {
- /*
- * we got the end of the one fat sector,
- * but we don't got we have(just one byte, we need two),
- * so store the low part, then read the next fat
- * sector, read the high part, then combine it.
- */
- lo = *(uint8_t *)(cs->data + offset);
- cs = getfatsector(fs, fat_sector + 1);
- hi = *(uint8_t *)cs->data;
- next_cluster = (hi << 8) + lo;
- } else
- next_cluster = *(uint16_t *)(cs->data + offset);
-
- if (clust_num & 0x0001)
- next_cluster >>= 4; /* cluster number is ODD */
- else
- next_cluster &= 0x0fff; /* cluster number is EVEN */
- if (next_cluster > 0x0ff0)
- goto fail;
- break;
-
+ fat_sector = (clust_num + clust_num / 2) >> SECTOR_SHIFT;
+ cs = get_fat_sector(fs, fat_sector);
+ offset = (clust_num * 3 / 2) & ((1 << SECTOR_SHIFT) - 1);
+ if (offset == 0x1ff) {
+ /*
+ * we got the end of the one fat sector,
+ * but we don't got we have(just one byte, we need two),
+ * so store the low part, then read the next fat
+ * sector, read the high part, then combine it.
+ */
+ lo = *(uint8_t *)(cs->data + offset);
+ cs = get_fat_sector(fs, fat_sector + 1);
+ hi = *(uint8_t *)cs->data;
+ next_cluster = (hi << 8) + lo;
+ } else {
+ next_cluster = *(uint16_t *)(cs->data + offset);
+ }
+
+ if (clust_num & 0x0001)
+ next_cluster >>= 4; /* cluster number is ODD */
+ else
+ next_cluster &= 0x0fff; /* cluster number is EVEN */
+ if (next_cluster > 0x0ff0)
+ goto fail;
+ break;
+
case FAT16:
- fat_sector = clust_num >> (SECTOR_SHIFT - 1);
- offset = clust_num & ((1 << (SECTOR_SHIFT-1)) -1);
- cs = getfatsector(fs, fat_sector);
- next_cluster = ((uint16_t *)cs->data)[offset];
- if (next_cluster > 0xfff0)
- goto fail;
- break;
-
+ fat_sector = clust_num >> (SECTOR_SHIFT - 1);
+ offset = clust_num & ((1 << (SECTOR_SHIFT-1)) -1);
+ cs = get_fat_sector(fs, fat_sector);
+ next_cluster = ((uint16_t *)cs->data)[offset];
+ if (next_cluster > 0xfff0)
+ goto fail;
+ break;
+
case FAT32:
- fat_sector = clust_num >> (SECTOR_SHIFT - 2);
- offset = clust_num & ((1 << (SECTOR_SHIFT-2)) -1);
- cs = getfatsector(fs, fat_sector);
- next_cluster = ((uint32_t *)cs->data)[offset] & 0x0fffffff;
- if (next_cluster > 0x0ffffff0)
- goto fail;
- break;
+ fat_sector = clust_num >> (SECTOR_SHIFT - 2);
+ offset = clust_num & ((1 << (SECTOR_SHIFT-2)) -1);
+ cs = get_fat_sector(fs, fat_sector);
+ next_cluster = ((uint32_t *)cs->data)[offset] & 0x0fffffff;
+ if (next_cluster > 0x0ffffff0)
+ goto fail;
+ break;
}
return next_cluster;
- fail:
+fail:
/* got an unexcepted cluster number, so return ZERO */
return 0;
}
-
-/*
- * given a sector on input, return the next sector of the
- * same filesystem object, which may be the root directory or a
- * cluster chain. Returns EOF.
- *
- */
-static sector_t nextsector(struct fs_info *fs, sector_t sector)
+static sector_t get_next_sector(struct fs_info* fs, uint32_t sector)
{
+ sector_t data_area = FAT_SB(fs)->data;
sector_t data_sector;
uint32_t cluster;
- if (sector < DataArea) {
- sector ++;
- /* if we reached the end of root area */
- if (sector == DataArea)
- sector = 0; /* return 0 */
- return sector;
+ if (sector < data_area) {
+ sector++;
+ /* if we reached the end of root area */
+ if (sector == data_area)
+ sector = 0; /* return 0 */
+ return sector;
}
- data_sector = sector - DataArea;
- if ((data_sector+1) & ClustMask) /* in a cluster */
- return (++sector);
+ data_sector = sector - data_area;
+ if ((data_sector + 1) & FAT_SB(fs)->clust_mask) /* in a cluster */
+ return ++sector;
- /* got a new cluster */
- cluster = nextcluster(fs, (data_sector >> ClustShift) + 2);
+ /* get a new cluster */
+ cluster = get_next_cluster(fs, (data_sector >> FAT_SB(fs)->clust_shift) + 2);
if (!cluster )
- return 0;
+ return 0;
/* return the start of the new cluster */
- sector = ((cluster - 2) << ClustShift) + DataArea;
+ sector = ((cluster - 2) << FAT_SB(fs)->clust_shift) + data_area;
return sector;
}
-
-
-
+/*
+ * Here comes the place I don't like VFAT fs most; if we need seek
+ * the file to the right place, we need get the right sector address
+ * from begining everytime! Since it's a kind a signle link list, we
+ * need to traver from the head-node to find the right node in that list.
+ *
+ * What a waste of time!
+ */
+static sector_t get_the_right_sector(struct file *file)
+{
+ int i = 0;
+ int sector_pos = file->offset >> SECTOR_SHIFT;
+ sector_t sector = *file->inode->data;
+
+ for (; i < sector_pos; i++)
+ sector = get_next_sector(file->fs, sector);
+
+ return sector;
+}
/**
* __getfssec:
@@ -224,15 +164,11 @@ static sector_t nextsector(struct fs_info *fs, sector_t sector)
* and will correct the situation if it does, UNLESS *sectos* cross
* 64K boundaries.
*
- * @param: buf
- * @param: file structure
- * @param: sectors
- *
*/
static void __getfssec(struct fs_info *fs, char *buf,
- struct open_file_t *file, uint32_t sectors)
+ struct file *file, uint32_t sectors)
{
- sector_t curr_sector = file->file_sector;
+ sector_t curr_sector = get_the_right_sector(file);
sector_t frag_start , next_sector;
uint32_t con_sec_cnt;
struct disk *disk = fs->fs_dev->disk;
@@ -249,7 +185,7 @@ static void __getfssec(struct fs_info *fs, char *buf,
if (sectors == 0)
break;
- next_sector = nextsector(fs, curr_sector);
+ next_sector = get_next_sector(fs, curr_sector);
if (!next_sector)
break;
}while(next_sector == (++curr_sector));
@@ -261,16 +197,14 @@ static void __getfssec(struct fs_info *fs, char *buf,
/* do read */
disk->rdwr_sectors(disk, buf, frag_start, con_sec_cnt, 0);
- buf += con_sec_cnt << 9;/* adjust buffer pointer */
+ buf += con_sec_cnt << SECTOR_SHIFT;/* adjust buffer pointer */
if (!sectors)
break;
- //curr_sector --; /* this is the last sector actually read */
+
curr_sector = next_sector;
}
- /* update the file_sector filed for the next read */
- file->file_sector = nextsector(fs, curr_sector);
}
@@ -279,32 +213,34 @@ static void __getfssec(struct fs_info *fs, char *buf,
* get multiple sectors from a file
*
* @param: buf, the buffer to store the read data
- * @param: gfile, the file structure pointer
+ * @param: file, the file structure pointer
* @param: sectors, number of sectors wanna read
* @param: have_more, set one if has more
*
* @return: number of bytes read
*
*/
-static uint32_t vfat_getfssec(struct file *gfile, char *buf, int sectors,
+static uint32_t vfat_getfssec(struct file *file, char *buf, int sectors,
bool *have_more)
{
- uint32_t bytes_read = sectors << SECTOR_SHIFT;
- struct open_file_t *file = gfile->open_file;
- struct fs_info *fs = gfile->fs;
-
- if (sectors > file->file_left)
- sectors = file->file_left;
+ struct fs_info *fs = file->fs;
+ uint32_t bytes_left = file->inode->size - file->offset;
+ uint32_t bytes_read = sectors << fs->sector_shift;
+ int sector_left;
+
+ sector_left = (bytes_left + SECTOR_SIZE(fs) - 1) >> fs->sector_shift;
+ if (sectors > sector_left)
+ sectors = sector_left;
__getfssec(fs, buf, file, sectors);
- if (bytes_read >= file->file_bytesleft) {
- bytes_read = file->file_bytesleft;
+ if (bytes_read >= bytes_left) {
+ bytes_read = bytes_left;
*have_more = 0;
- } else
- *have_more = 1;
- file->file_bytesleft -= bytes_read;
- file->file_left -= sectors;
+ } else {
+ *have_more = 1;
+ }
+ file->offset += bytes_read;
return bytes_read;
}
@@ -356,72 +292,56 @@ static void vfat_mangle_name(char *dst, const char *src)
for (; i > 0; i --)
*dst++ = '\0';
}
-
+
/*
- * Mangle a dos filename component pointed to by FILENAME
- * into MangleBuf; ends on encountering any whitespace or
- * slash.
- *
- * WARNING: saves pointers into the buffer for longname matchs!
- */
-/**
- * for now, it can't handle this case:
- * xyxzxyxjfdkfjdjf.txt as it will just output the first 11 chars
- * but not care the dot char at the later, so I think we need do
- * this, but it seems that the SYSLINUX doesn't do it, so I will
- * make it stay as what it was orignal.
- *
+ * Mangle a normal style string to DOS style string.
*/
-static void mangle_dos_name(char *MangleBuf, char *filename)
-{
-
- char *dst = MangleBuf;
- char *src = filename;
+static void mangle_dos_name(char *mangle_buf, char *src)
+{
+ char *dst = mangle_buf;
int i = 0;
unsigned char c;
- NameStart = filename;
-
for (; i < 11; i ++)
- MangleBuf[i] = ' ';
+ mangle_buf[i] = ' ';
for (i = 0; i < 11; i++) {
- c = *src ++;
-
- if ((c <= ' ') || (c == '/'))
- break;
-
- if (c == '.') {
- dst = &MangleBuf[8];
- i = 7;
- continue;
- }
-
- if (c >= 'a' && c <= 'z')
- c -= 32;
- if ((c == 0xe5) && (i == 11))
- c = 0x05;
-
- *dst++ = c;
+ c = *src ++;
+
+ if ((c <= ' ') || (c == '/'))
+ break;
+
+ if (c == '.') {
+ dst = &mangle_buf[8];
+ i = 7;
+ continue;
+ }
+
+ if (c >= 'a' && c <= 'z')
+ c -= 32;
+ if ((c == 0xe5) && (i == 11))
+ c = 0x05;
+
+ *dst++ = c;
}
- MangleBuf[12] = '\0';
-
- while((*src != '/') && (*src > ' '))
- src ++;
-
- NameLen = src - filename;
+ mangle_buf[11] = '\0';
}
+
+/* try with the biggest long name */
+static char long_name[0x40 * 13];
+static char entry_name[14];
+
static void unicode_to_ascii(char *entry_name, uint16_t *unicode_buf)
{
int i = 0;
for (; i < 13; i++) {
- if (unicode_buf[i] == 0xffff) {
- entry_name[i] = '\0';
- return;
- }
- entry_name[i] = (char)unicode_buf[i];
+ if (unicode_buf[i] == 0xffff) {
+ entry_name[i] = '\0';
+ return;
+ }
+ entry_name[i] = (char)unicode_buf[i];
}
}
@@ -433,384 +353,322 @@ static void long_entry_name(struct fat_long_name_entry *dir)
{
uint16_t unicode_buf[13];
- memcpy(unicode_buf, dir->name1, 5 * 2);
- memcpy(unicode_buf + 5, dir->name2, 6 * 2);
- memcpy(unicode_buf + 11,dir->name3, 2 * 2);
-
- unicode_to_ascii(entry_name, unicode_buf);
+ memcpy(unicode_buf, dir->name1, 5 * 2);
+ memcpy(unicode_buf + 5, dir->name2, 6 * 2);
+ memcpy(unicode_buf + 11, dir->name3, 2 * 2);
+ unicode_to_ascii(entry_name, unicode_buf);
}
static uint8_t get_checksum(char *dir_name)
{
int i;
- uint8_t sum=0;
+ uint8_t sum = 0;
- for (i=11; i; i--)
- sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++;
+ for (i = 11; i; i--)
+ sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++;
return sum;
}
+
/* compute the first sector number of one dir where the data stores */
static inline sector_t first_sector(struct fat_dir_entry *dir)
{
- uint32_t first_clust, sector;
+ struct fat_sb_info *sbi = FAT_SB(this_fs);
+ uint32_t first_clust;
+ sector_t sector;
first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low;
- sector = ((first_clust - 2) << ClustShift) + DataArea;
+ sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data;
return sector;
}
+static inline int get_inode_mode(uint8_t attr)
+{
+ if (attr == FAT_ATTR_DIRECTORY)
+ return I_DIR;
+ else
+ return I_FILE;
+}
-/**
- * search a specific directory for a pre-mangled filename in
- * MangleBuf, in the directory starting in sector SECTOR
- *
- * 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).
- *
- * @param: MangleBuf
- * @param: dir_sector, directory sector
- *
- * @out: file pointer
- * @out: file length (MAY BE ZERO!)
- * @out: file attribute
- *
- */
-static struct open_file_t*
-search_dos_dir(struct fs_info *fs, char *MangleBuf,
- uint32_t dir_sector, uint32_t *file_len, uint8_t *attr)
+
+static struct inode *vfat_find_entry(char *dname, struct inode *dir)
{
- struct open_file_t* file;
- struct cache_struct* cs;
- struct fat_dir_entry *dir;
- struct fat_long_name_entry *long_dir;
-
- uint8_t VFATInit, VFATNext, VFATCsum;
- uint8_t id;
- uint32_t slots;
- uint32_t entries;
+ struct inode *inode = new_fat_inode();
+ struct fat_dir_entry *de;
+ struct fat_long_name_entry *long_de;
+ struct cache_struct *cs;
+
+ char mangled_name[12] = {0, };
+ sector_t dir_sector = *dir->data;
+
+ uint8_t vfat_init, vfat_next, vfat_csum = 0;
+ uint8_t id;
+ int slots;
+ int entries;
int checksum;
-
- file = allocate_file();
- if (!file)
- return NULL;
+ int long_match = 0;
- /*
- * Compute the value of a possible VFAT longname
- * "last" entry (which, of coures, comes first ...)
- */
- slots = (NameLen + 12) / 13;
- slots |= 0x40;
- VFATInit = slots;
- VFATNext = slots;
-
- do {
- cs = get_cache_block(fs->fs_dev, dir_sector);
- dir = (struct fat_dir_entry *)cs->data;
- entries = SECTOR_SIZE / 32;
-
- /* scan all the entries in a sector */
- do {
- if (dir->name[0] == 0)
- return NULL; /* Hit directory high water mark */
-
- if (dir->attr == 0x0f) {
- /* it's a long name entry */
- long_dir = (struct fat_long_name_entry *)dir;
- id = long_dir->id;
- if (id !=VFATNext)
- goto not_match;
-
- if (id & 0x40) {
- /*get the initial checksum value*/
- VFATCsum = long_dir->checksum;
- } else {
- if (long_dir->checksum != VFATCsum)
- goto not_match;
- }
-
- id &= 0x3f;
- VFATNext = --id;
-
- /* got the long entry name */
- long_entry_name(long_dir);
- memcpy(long_name + id * 13, entry_name, 13);
-
- /*
- * if we got the last entry?
- * if so, check it, or go on with the next entry
- */
- if (id == 0) {
- if (strcmp(long_name, NameStart))
- goto not_match;
- }
-
- goto next_entry;
-
- } else {
- /* it's a short entry */
- if (dir->attr & 0x08) /* ingore volume labels */
- goto not_match;
-
-
- /* If we have a long name match, then VFATNext must be 0 */
- if (!VFATNext) {
- /*
- * we already have a VFAT long name match, however,
- * the match is only valid if the checksum matchs.
- */
- checksum = get_checksum(dir->name);
- if (checksum == VFATCsum)
- goto found; /* got a match on long name */
-
- } else {
- if (strncmp(MangleBuf, dir->name, 11) == 0)
- goto found;
- }
- }
-
- not_match:/* find it again */
- VFATNext = VFATInit;
-
- next_entry:
- dir ++;
-
- }while (--entries);
-
- dir_sector = nextsector(fs, dir_sector);
-
- }while (dir_sector); /* scan another secotr */
-
- found:
- *file_len = file->file_bytesleft = dir->file_size;
- file->file_sector = first_sector(dir);
- *attr = dir->attr;
+ slots = (strlen(dname) + 12) / 13 ;
+ slots |= 0x40;
+ vfat_init = vfat_next = slots;
+
+ while (1) {
+ cs = get_cache_block(this_fs->fs_dev, dir_sector);
+ de = (struct fat_dir_entry *)cs->data;
+ entries = 1 << (this_fs->sector_shift - 5);
+
+ while(entries--) {
+ if (de->name[0] == 0)
+ return NULL;
+
+ if (de->attr == 0x0f) {
+ /*
+ * It's a long name entry.
+ */
+ long_de = (struct fat_long_name_entry *)de;
+ id = long_de->id;
+ if (id != vfat_next)
+ goto not_match;
+
+ if (id & 0x40) {
+ /* get the initial checksum value */
+ vfat_csum = long_de->checksum;
+ id &= 0x3f;
+
+ /* ZERO the long_name buffer */
+ memset(long_name, 0, sizeof long_name);
+ } else {
+ if (long_de->checksum != vfat_csum)
+ goto not_match;
+ }
+
+ vfat_next = --id;
+
+ /* got the long entry name */
+ long_entry_name(long_de);
+ memcpy(long_name + id * 13, entry_name, 13);
+
+ /*
+ * If we got the last entry, check it.
+ * Or, go on with the next entry.
+ */
+ if (id == 0) {
+ if (strcmp(long_name, dname))
+ goto not_match;
+ long_match = 1;
+ }
+
+ de++;
+ continue; /* Try the next entry */
+ } else {
+ /*
+ * It's a short entry
+ */
+ if (de->attr & 0x08) /* ignore volume labels */
+ goto not_match;
+
+ if (long_match == 1) {
+ /*
+ * We already have a VFAT long name match. However, the
+ * match is only valid if the checksum matches.
+ *
+ * Well, let's trun the long_match flag off first.
+ */
+ long_match = 0;
+ checksum = get_checksum(de->name);
+ if (checksum == vfat_csum)
+ goto found; /* Got it */
+ } else {
+ if (mangled_name[0] == 0) {
+ /* We haven't mangled it, mangle it first. */
+ mangle_dos_name(mangled_name, dname);
+ }
+
+ if (!strncmp(mangled_name, de->name, 11))
+ goto found;
+ }
+ }
+
+ not_match:
+ vfat_next = vfat_init;
+
+ de++;
+ }
+
+ /* Try with the next sector */
+ dir_sector = get_next_sector(this_fs, dir_sector);
+ if (!dir_sector)
+ return NULL;
+ }
- return file;
+found:
+ inode->size = de->file_size;
+ *inode->data = first_sector(de);
+ inode->mode = get_inode_mode(de->attr);
+
+ return inode;
}
-
-
-/**
- * open a file
- *
- * @param: filename, the file we wanna open
- * @param: file_len, to return the file length
- *
- * @return: return the file structure on successful, or NULL.
- *
- */
-static void vfat_searchdir(char *filename, struct file *file)
+static struct inode *vfat_iget_root(void)
{
- sector_t dir_sector;
- uint32_t file_len = 0;
- uint8_t attr = 0;
- char *p;
- struct open_file_t *open_file = NULL;
-
- dir_sector = CurrentDir;
- if (*filename == '/') {
- dir_sector = RootDir;
- if (*(filename + 1) == 0) /* root dir is what we need */
- goto found_dir;
- }
-
- while (*filename) {
- if (*filename == '/')
- filename++; /* skip '/' */
- p = filename;
- if (*p == 0)
- break;
- PrevDir = dir_sector;
-
- /* try to find the end */
- while ((*p > ' ') && (*p != '/'))
- p ++;
-
- if (filename == p) {
- /* found a dir */
- dir_sector = PrevDir;
- goto found_dir;
- }
-
- mangle_dos_name(MangleBuf, filename);
- /* close it before open a new dir file */
- if (open_file)
- close_pvt(open_file);
- open_file = search_dos_dir(file->fs, MangleBuf, dir_sector, &file_len, &attr);
- if (!open_file)
- goto fail;
-
- dir_sector = open_file->file_sector;
- filename = p;
- }
+ struct inode *inode = new_fat_inode();
+ int root_size = FAT_SB(this_fs)->root_size;
- if (attr & 0x10) {
- found_dir:
- open_file = alloc_fill_dir(dir_sector);
- } else if ((attr & 0x18) || (file_len == 0)) {
- fail:
- file_len = 0;
- open_file = NULL;
- } else {
- open_file->file_bytesleft = file_len;
- open_file->file_left = (file_len + SECTOR_SIZE -1) >> SECTOR_SHIFT;
- }
-
- file->file_len = file_len;
- file->open_file = open_file;
+ inode->size = root_size << this_fs->sector_shift;
+ *inode->data = FAT_SB(this_fs)->root;
+ inode->mode = I_DIR;
+
+ return inode;
}
-/*
- * The open dir function, just call the searchdir function directly.
- * I don't think we need call the mangle_name function first
- */
-void vfat_opendir(com32sys_t *regs)
+static struct inode *vfat_iget(char *dname, struct inode *parent)
{
- char *src = MK_PTR(regs->es, regs->esi.w[0]);
- char *dst = MK_PTR(regs->ds, regs->edi.w[0]);
- strcpy(dst, src);
- searchdir(regs);
+ return vfat_find_entry(dname, parent);
}
-/*
- * read one file from a directory; return the newly read de structure
- */
-struct dirent* vfat_readdir(struct file *dir)
+static struct dirent * vfat_readdir(struct file *file)
{
- uint32_t sector, sec_off;
- /* make it to be 1 to check if we have met a long name entry before */
- uint8_t id = 1;
- uint8_t init_id, next_id;
- uint8_t checksum = 0;
- uint8_t entries_left;
- int i;
- static struct dirent de;
- char *de_name = de.d_name;
- struct cache_struct *cs;
- struct fat_dir_entry *fat_dir;
- struct fat_long_name_entry *long_dir;
- struct open_file_t *file = dir->open_file;
- struct fs_info *fs = dir->fs;
-
- sector = file->file_sector;
- sec_off = file->file_bytesleft;
- if (!sector)
- return NULL;
- entries_left = (SECTOR_SIZE - sec_off) >> 5;
+ struct fs_info *fs = file->fs;
+ struct dirent *dirent;
+ struct fat_dir_entry *de;
+ struct fat_long_name_entry *long_de;
+ struct cache_struct *cs;
+
+ sector_t sector = get_the_right_sector(file);
+
+ uint8_t vfat_init, vfat_next, vfat_csum;
+ uint8_t id;
+ int entries_left;
+ int checksum;
+ int long_entry = 0;
+ int sec_off = file->offset & ((1 << fs->sector_shift) - 1);
+
cs = get_cache_block(fs->fs_dev, sector);
- fat_dir = (struct fat_dir_entry *)(cs->data + sec_off);/* resume last position in sector */
+ de = (struct fat_dir_entry *)(cs->data + sec_off);
+ entries_left = ((1 << fs->sector_shift) - sec_off) >> 5;
while (1) {
- if (!entries_left) {
- sector = nextsector(fs, sector);
- if (!sector)
- return NULL;
- cs = get_cache_block(fs->fs_dev, sector);
- fat_dir = (struct fat_dir_entry *)cs->data;
- }
+ while(entries_left--) {
+ if (de->name[0] == 0)
+ return NULL;
+ if ((uint8_t)de->name[0] == 0xe5)
+ goto invalid;
+
+ if (de->attr == 0x0f) {
+ /*
+ * It's a long name entry.
+ */
+ long_de = (struct fat_long_name_entry *)de;
+ id = long_de->id;
- if (fat_dir->name[0] == 0)
- return NULL;
- if (fat_dir->attr == FAT_ATTR_LONG_NAME) {
- /* it's a long name */
- long_dir = (struct fat_long_name_entry *)fat_dir;
-
- if (long_dir->id & 0x40) {
- checksum = long_dir->checksum;
- init_id = id = long_dir->id & 0x3f;
- id--;
- } else {
- next_id = (long_dir->id & 0x3f) - 1;
- id--;
- if (id != next_id || long_dir->checksum != checksum)
- goto next_entry;
- }
-
- long_entry_name(long_dir);
- memcpy(de_name + id * 13, entry_name, 13);
-
- /*
- * we need go on with the next entry
- * and we will fall through to next entry
- */
-
- } else {
- /* it's a short entry */
-
- if (!id) {
- /* Got a long name match */
- if (get_checksum(fat_dir->name) != checksum)
- goto next_entry;
+ if (id & 0x40) {
+ /* init vfat_csum and vfat_init */
+ vfat_csum = long_de->checksum;
+ id &= 0x3f;
+ vfat_init = id;
+
+ /* ZERO the long_name buffer */
+ memset(long_name, 0, sizeof long_name);
+ } else {
+ if (long_de->checksum != vfat_csum ||
+ id != vfat_next)
+ goto invalid;
+ }
- break;
+ vfat_next = --id;
+
+ /* got the long entry name */
+ long_entry_name(long_de);
+ memcpy(long_name + id * 13, entry_name, 13);
+
+ if (id == 0)
+ long_entry = 1;
+
+ de++;
+ file->offset += sizeof(struct fat_dir_entry);
+ continue; /* Try the next entry */
+ } else {
+ /*
+ * It's a short entry
+ */
+ if (de->attr & 0x08) /* ignore volume labels */
+ goto invalid;
+
+ if (long_entry == 1) {
+ /* Got a long entry */
+ checksum = get_checksum(de->name);
+ if (checksum == vfat_csum)
+ goto got;
+ } else {
+ /* Use the long_name buffer to store a short one. */
+ int i;
+ char *p = long_name;
+
+ for (i = 0; i < 8; i++) {
+ if (de->name[i] == ' ')
+ break;
+ *p++ = de->name[i];
+ }
+ *p++ = '.';
+ if (de->name[8] == ' ') {
+ *--p = '\0';
+ } else {
+ for (i = 8; i < 11; i++) {
+ if (de->name[i] == ' ')
+ break;
+ *p++ = de->name[i];
+ }
+ *p = '\0';
+ }
+
+ goto got;
+ }
}
-
- if (fat_dir->attr & FAT_ATTR_VOLUME_ID ||
- get_checksum(fat_dir->name) != checksum )
- goto next_entry;
-
- for(i = 0; i < 8; i ++) {
- if (fat_dir->name[i] == ' ')
- break;
- *de_name++ = fat_dir->name[i];
- }
- *de_name++ = '.';
- for (i = 8; i < 11; i ++) {
- if (fat_dir->name[i] == ' ')
- break;
- *de_name ++ = fat_dir->name[i];
- }
- /* check if we have got an extention */
- if (*(de_name - 1) == '.')
- *(de_name - 1) = '\0';
- else
- *de_name = '\0';
- break;
- }
-
- next_entry:
- entries_left --;
- fat_dir ++;
+ invalid:
+ de++;
+ file->offset += sizeof(struct fat_dir_entry);
+ }
+
+ /* Try with the next sector */
+ sector = get_next_sector(fs, sector);
+ if (!sector)
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, sector);
+ de = (struct fat_dir_entry *)cs->data;
+ entries_left = 1 << (fs->sector_shift - 5);
}
- /* found what we want, fill the de structure */
- de.d_reclen = DIR_REC_LEN(de.d_name);
- de.d_type = fat_dir->attr;
-
- /* update the DIR structure */
- entries_left--;
- if (!entries_left) {
- sector = nextsector(fs, sector);
- file->file_bytesleft = 0;
- } else {
- file->file_bytesleft = SECTOR_SIZE - (entries_left << 5);
+got:
+ if (!(dirent = malloc(sizeof(*dirent)))) {
+ malloc_error("dirent structure in vfat_readdir");
+ return NULL;
}
- file->file_sector = sector;
+ dirent->d_ino = 0; /* Inode number is invalid to FAT fs */
+ dirent->d_off = file->offset;
+ dirent->d_reclen = 0;
+ dirent->d_type = get_inode_mode(de->attr);
+ strcpy(dirent->d_name, long_name);
- return &de;
+ file->offset += sizeof(*de); /* Update for next reading */
+
+ return dirent;
}
/* Load the config file, return 1 if failed, or 0 */
static int vfat_load_config(void)
{
- static const char syslinux_cfg1[] = "/boot/syslinux/syslinux.cfg";
- static const char syslinux_cfg2[] = "/syslinux/syslinux.cfg";
- static const char syslinux_cfg3[] = "/syslinux.cfg";
- static const char config_name[] = "syslinux.cfg";
- const char * const syslinux_cfg[] =
- { syslinux_cfg1, syslinux_cfg2, syslinux_cfg3 };
+ const char * const syslinux_cfg[] = {
+ "/boot/syslinux/syslinux.cfg",
+ "/syslinux/syslinux.cfg",
+ "/syslinux.cfg"
+ };
com32sys_t regs;
+ char *p;
int i = 0;
-
- *(uint16_t *)CurrentDirName = ROOT_DIR_WORD;
- CurrentDir = RootDir;
/*
* we use the ConfigName to pass the config path because
@@ -830,11 +688,12 @@ static int vfat_load_config(void)
printf("no config file found\n");
return 1; /* no config file */
}
-
- strcpy(ConfigName, config_name);
+
+ strcpy(ConfigName, "syslinux.cfg");
strcpy(CurrentDirName, syslinux_cfg[i]);
- CurrentDirName[strlen(syslinux_cfg[i])-strlen(config_name)] = '\0';
- CurrentDir = PrevDir;
+ p = strrchr(CurrentDirName, '/');
+ *(p + 1) = '\0'; /* In case we met '/syslinux.cfg' */
+
return 0;
}
@@ -847,49 +706,59 @@ static inline __constfunc uint32_t bsr(uint32_t num)
/* init. the fs meta data, return the block size in bits */
static int vfat_fs_init(struct fs_info *fs)
{
- int sectors_per_fat;
- uint32_t clust_num;
- int RootDirSize;
+ struct fat_bpb fat;
+ struct fat_sb_info *sbi;
struct disk *disk = fs->fs_dev->disk;
+ int sectors_per_fat;
+ uint32_t clust_num;
+ sector_t total_sectors;
- /* get the fat bpb information */
+ fs->sector_shift = fs->block_shift = disk->sector_shift;
disk->rdwr_sectors(disk, &fat, 0, 1, 0);
- TotalSectors = fat.bxSectors ? : fat.bsHugeSectors;
- FAT = fat.bxResSectors;
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi)
+ malloc_error("fat_sb_info structure");
+ fs->fs_info = sbi;
+ this_fs = fs;
sectors_per_fat = fat.bxFATsecs ? : fat.u.fat32.bxFATsecs_32;
- RootDir = RootDirArea = FAT + sectors_per_fat * fat.bxFATs;
- RootDirSize = (fat.bxRootDirEnts+SECTOR_SIZE/32-1) >> (SECTOR_SHIFT-5);
- DataArea = RootDirArea + RootDirSize;
-
- ClustShift = bsr(fat.bxSecPerClust);
- ClustByteShift = ClustShift + SECTOR_SHIFT;
- ClustMask = fat.bxSecPerClust - 1;
- ClustSize = fat.bxSecPerClust << SECTOR_SHIFT;
-
- clust_num = (TotalSectors - DataArea) >> ClustShift;
+ total_sectors = fat.bxSectors ? : fat.bsHugeSectors;
+
+ sbi->fat = fat.bxResSectors;
+ sbi->root = sbi->fat + sectors_per_fat * fat.bxFATs;
+ sbi->root_size = root_dir_size(&fat);
+ sbi->data = sbi->root + sbi->root_size;
+
+ sbi->clust_shift = bsr(fat.bxSecPerClust);
+ sbi->clust_byte_shift = sbi->clust_shift + fs->sector_shift;
+ sbi->clust_mask = fat.bxSecPerClust - 1;
+ sbi->clust_size = fat.bxSecPerClust << fs->sector_shift;
+
+ clust_num = (total_sectors - sbi->data) >> sbi->clust_shift;
if (clust_num < 4085)
- FATType = FAT12;
+ sbi->fat_type = FAT12;
else if (clust_num < 65525)
- FATType = FAT16;
- else
- FATType = FAT32;
+ sbi->fat_type = FAT16;
+ else
+ sbi->fat_type = FAT32;
/* for SYSLINUX, the cache is based on sector size */
- return SECTOR_SHIFT;
+ return fs->sector_shift;
}
const struct fs_ops vfat_fs_ops = {
.fs_name = "vfat",
- .fs_flags = 0,
+ .fs_flags = FS_USEMEM | FS_THISIND,
.fs_init = vfat_fs_init,
- .searchdir = vfat_searchdir,
+ .searchdir = NULL,
.getfssec = vfat_getfssec,
.close_file = vfat_close_file,
.mangle_name = vfat_mangle_name,
.unmangle_name = generic_unmangle_name,
.load_config = vfat_load_config,
- .opendir = vfat_opendir,
- .readdir = vfat_readdir
+ .readdir = vfat_readdir,
+ .iget_root = vfat_iget_root,
+ .iget_current = NULL,
+ .iget = vfat_iget,
};
diff --git a/core/fs/fat/fat_fs.h b/core/fs/fat/fat_fs.h
index 71c1d9a7..9453a67f 100644
--- a/core/fs/fat/fat_fs.h
+++ b/core/fs/fat/fat_fs.h
@@ -76,9 +76,26 @@ struct fat_bpb {
} __attribute__ ((packed)) u;
-} __attribute__ ((packed));
+ uint8_t pad[422]; /* padding to 512 Bytes (one sector) */
+} __attribute__ ((packed));
+/*
+ * The fat file system info in memory
+ */
+struct fat_sb_info {
+ sector_t fat; /* The FAT region */
+ sector_t root; /* The root dir region */
+ int root_size; /* The root dir size in sectores */
+ sector_t data; /* The data region */
+
+ int clust_shift; /* based on sectors */
+ int clust_byte_shift; /* based on bytes */
+ int clust_mask;
+ int clust_size;
+
+ int fat_type;
+} __attribute__ ((packed));
struct fat_dir_entry {
char name[11];
@@ -108,7 +125,21 @@ struct fat_long_name_entry {
uint16_t name3[2];
} __attribute__ ((packed));
+static inline struct fat_sb_info *FAT_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+/*
+ * Count the root dir size in sectors
+ */
+static inline int root_dir_size(struct fat_bpb *fat)
+{
+ int sector_size = 1 << SECTOR_SHIFT;
+
+ return (fat->bxRootDirEnts + sector_size / sizeof(struct fat_dir_entry)
+ - 1) >> (SECTOR_SHIFT - 5);
+}
#endif /* fat_fs.h */
diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
index e060b13d..1670e607 100644
--- a/core/fs/iso9660/iso9660.c
+++ b/core/fs/iso9660/iso9660.c
@@ -1,77 +1,44 @@
#include <stdio.h>
#include <string.h>
+#include <sys/dirent.h>
#include <core.h>
+#include <cache.h>
#include <disk.h>
#include <fs.h>
#include "iso9660_fs.h"
-#define DEBUG 1
-
-#define ISO_SECTOR_SHIFT 11
-#define ISO_SECTOR_SIZE (1 << ISO_SECTOR_SHIFT)
-#define ROOT_DIR_WORD 0x002f
-#define TRACKBUF_SIZE 8192
-
-struct open_file_t {
- sector_t file_sector;
- uint32_t file_bytesleft;
- uint32_t file_left;
-};
-static struct open_file_t Files[MAX_OPEN];
-
-struct dir_t {
- uint32_t dir_lba; /* Directory start (LBA) */
- uint32_t dir_len; /* Length in bytes */
- uint32_t dir_clust; /* Length in clusters */
-};
-static struct dir_t RootDir;
-static struct dir_t CurrentDir;
-
-static uint16_t BufSafe = TRACKBUF_SIZE >> ISO_SECTOR_SHIFT;
-
-static char ISOFileName[64]; /* ISO filename canonicalizatin buffer */
-static char *ISOFileNameEnd = &ISOFileName[64];
-
-/*
- * use to store the block shift, since we treat the hd-mode as 512 bytes
- * sector size, 2048 bytes block size. we still treat the cdrom as 2048
- * bytes sector size and also the block size.
- */
-static int block_shift;
-
-/*
- * allocate a file structure
- *
- */
-static struct open_file_t *allocate_file(void)
+static struct inode *new_iso_inode(void)
{
- struct open_file_t *file = Files;
- int i;
-
- for (i = 0; i < MAX_OPEN; i++) {
- if ( file->file_sector == 0 ) /* found it */
- return file;
- file++;
+ struct inode *inode = malloc(sizeof(*inode));
+
+ if (!inode) {
+ malloc_error("inode structure in new_iso_inode");
+ return NULL;
}
-
- return NULL; /* not found */
+ memset(inode, 0, sizeof(*inode));
+
+ inode->data = malloc(sizeof(uint32_t));
+ if (!inode) {
+ malloc_error("inode->data in new_iso_inode");
+ free(inode);
+ return NULL;
+ }
+
+ return inode;
}
-/**
- * close_file:
- *
- * Deallocates a file structure
- *
- */
-static inline void close_pvt(struct open_file_t *file)
+static void iso_close_file(struct file *file)
{
- file->file_sector = 0;
+ if (file->inode) {
+ file->offset = 0;
+ free_inode(file->inode);
+ }
}
-static void iso_close_file(struct file *file)
+static inline struct iso_sb_info * ISO_SB(struct fs_info *fs)
{
- close_pvt(file->open_file);
+ return fs->fs_info;
}
/*
@@ -120,417 +87,375 @@ static void iso_mangle_name(char *dst, const char *src)
*dst++ = '\0';
}
-/**
- * compare the names de_name and file_name and report if they are
- * equal from an ISO 9600 perspective.
- *
- * @param: de_name, the name from the file system.
- * @param: len, the length of de_name, and will return the real name of the de_name
- * ';' and other terminates excluded.
- * @param: file_name, the name we want to check, is expected to end with a null
- *
- * @return: 1 on match, or 0.
- *
- */
-static int iso_compare_names(char *de_name, int *len, char *file_name)
+static int iso_convert_name(char *dst, char *src, int len)
{
- char *p = ISOFileName;
- char c1, c2;
-
int i = 0;
-
- while ( (i < *len) && *de_name && (*de_name != ';') && (p < ISOFileNameEnd - 1) ) {
- *p++ = *de_name++;
- i++;
+ char c;
+
+ for (; i < len; i++) {
+ c = src[i];
+ if (!c)
+ break;
+
+ /* remove ';1' in the end */
+ if (c == ';' && i == len - 2 && src[i + 1] == '1')
+ break;
+ /* convert others ';' to '.' */
+ if (c == ';')
+ c = '.';
+ *dst++ = c;
}
-
- /* Remove terminal dots */
- while ( *(p-1) == '.' ) {
- if ( *len <= 2 )
- break;
-
- if ( p <= ISOFileName )
- break;
- p --;
- i--;
+
+ /* Then remove the terminal dots */
+ while (*(dst - 1) == '.') {
+ if (i <= 2)
+ break;
+ dst--;
+ i--;
}
+ *dst = 0;
+
+ return i;
+}
- if ( i <= 0 )
- return 0;
-
- *p = '\0';
-
- /* return the 'real' length of de_name */
- *len = i;
-
- p = ISOFileName;
-
- /* i is the 'real' name length of file_name */
- while ( i ) {
- c1 = *p++;
- c2 = *file_name++;
-
- if ( (c1 == 0) && (c2 == 0) )
- return 1; /* success */
-
- else if ( (c1 == 0) || ( c2 == 0 ) )
- return 0;
-
- c1 |= 0x20;
- c2 |= 0x20; /* convert to lower case */
- if ( c1 != c2 )
- return 0;
- i --;
+/*
+ * Unlike strcmp, it does return 1 on match, or reutrn 0 if not match.
+ */
+static int iso_compare_name(char *de_name, int len, char *file_name)
+{
+ char iso_file_name[256];
+ char *p = iso_file_name;
+ char c1, c2;
+ int i;
+
+ i = iso_convert_name(iso_file_name, de_name, len);
+
+ if (i != (int)strlen(file_name))
+ return 0;
+
+ while (i--) {
+ c1 = *p++;
+ c2 = *file_name++;
+
+ /* convert to lower case */
+ c1 |= 0x20;
+ c2 |= 0x20;
+ if (c1 != c2)
+ return 0;
}
-
+
return 1;
}
-static inline int cdrom_read_sectors(struct disk *disk, void *buf, int block, int count)
+static inline int cdrom_read_blocks(struct disk *disk, void *buf,
+ int block, int blocks)
{
- /* changed those to _sector_ */
- block <<= block_shift;
- count <<= block_shift;
- return disk->rdwr_sectors(disk, buf, block, count, 0);
+ return disk->rdwr_sectors(disk, buf, block, blocks, 0);
}
-/**
+/*
* Get multiple clusters from a file, given the file pointer.
- *
- * @param: buf
- * @param: file, the address of the open file structure
- * @param: sectors, how many we want to read at once
- * @param: have_more, to indicate if we have reach the end of the file
- *
*/
-static uint32_t iso_getfssec(struct file *gfile, char *buf,
- int sectors, bool *have_more)
+static uint32_t iso_getfssec(struct file *file, char *buf,
+ int blocks, bool *have_more)
{
- uint32_t bytes_read = sectors << ISO_SECTOR_SHIFT;
- struct open_file_t *file = gfile->open_file;
- struct disk *disk = gfile->fs->fs_dev->disk;
-
- if ( sectors > file->file_left )
- sectors = file->file_left;
-
- cdrom_read_sectors(disk, buf, file->file_sector, sectors);
-
- file->file_sector += sectors;
- file->file_left -= sectors;
+ struct fs_info *fs = file->fs;
+ struct disk *disk = fs->fs_dev->disk;
+ uint32_t bytes_read = blocks << fs->block_shift;
+ uint32_t bytes_left = file->inode->size - file->offset;
+ uint32_t blocks_left = (bytes_left + BLOCK_SIZE(file->fs) - 1)
+ >> file->fs->block_shift;
+ block_t block = *file->inode->data + (file->offset >> fs->block_shift);
+
+ if (blocks > blocks_left)
+ blocks = blocks_left;
+ cdrom_read_blocks(disk, buf, block, blocks);
- if ( bytes_read >= file->file_bytesleft ) {
- bytes_read = file->file_bytesleft;
+ if (bytes_read >= bytes_left) {
+ bytes_read = bytes_left;
*have_more = 0;
- } else
+ } else {
*have_more = 1;
- file->file_bytesleft -= bytes_read;
-
+ }
+
+ file->offset += bytes_read;
return bytes_read;
}
-
-
/*
- * find a file or directory with name within the _dir_ directory.
- *
- * the return value will tell us what we find, it's a file or dir?
- * on 1 be dir, 2 be file, 0 be error. res will return the result.
- *
+ * Find a entry in the specified dir with name _dname_.
*/
-static int do_search_dir(struct fs_info *fs, struct dir_t *dir,
- char *name, uint32_t *file_len, void **res)
+static struct iso_dir_entry *iso_find_entry(char *dname, struct inode *inode)
{
- struct open_file_t *file;
+ block_t dir_block = *inode->data;
+ int i = 0, offset = 0;
+ char *de_name;
+ int de_name_len, de_len;
struct iso_dir_entry *de;
struct iso_dir_entry tmpde;
- struct file xfile;
-
- uint32_t offset = 0; /* let's start it with the start */
- uint32_t file_pos = 0;
- char *de_name;
- int de_len;
- int de_name_len;
- bool have_more;
-
- file = allocate_file();
- if ( !file )
- return 0;
-
- file->file_left = dir->dir_clust;
- file->file_sector = dir->dir_lba;
-
- xfile.fs = fs;
- xfile.open_file = file;
-
- iso_getfssec(&xfile, trackbuf, BufSafe, &have_more);
- de = (struct iso_dir_entry *)trackbuf;
-
- while ( file_pos < dir->dir_len ) {
- int found = 0;
-
- if ( (char *)de >= (char *)(trackbuf + TRACKBUF_SIZE) ) {
- if ( !have_more )
- return 0;
-
- iso_getfssec(&xfile, trackbuf, BufSafe, &have_more);
- offset = 0;
- }
-
- de = (struct iso_dir_entry *) (trackbuf + offset);
-
- de_len = de->length;
-
- if ( de_len == 0) {
- offset = file_pos = (file_pos+ISO_SECTOR_SIZE) & ~(ISO_SECTOR_SIZE-1);
- continue;
- }
-
-
- offset += de_len;
-
- /* Make sure we have a full directory entry */
- if ( offset >= TRACKBUF_SIZE ) {
- int slop = TRACKBUF_SIZE - offset + de_len;
- memcpy(&tmpde, de, slop);
- offset &= TRACKBUF_SIZE - 1;
- file->file_sector++;
- if ( offset ) {
- if ( !have_more )
- return 0;
- iso_getfssec(&xfile, trackbuf, BufSafe, &have_more);
- memcpy((void*)&tmpde + slop, trackbuf, offset);
- }
- de = &tmpde;
- }
-
- if ( de_len < 33 ) {
- printf("Corrutped directory entry in sector %d\n", file->file_sector);
- return 0;
- }
-
- de_name_len = de->name_len;
- de_name = (char *)((void *)de + 0x21);
-
-
- if ( (de_name_len == 1) && (*de_name == 0) ) {
- found = iso_compare_names(".", &de_name_len, name);
-
- } else if ( (de_name_len == 1) && (*de_name == 1) ) {
- de_name_len = 2;
- found = iso_compare_names("..", &de_name_len, name);
-
- } else
- found = iso_compare_names(de_name, &de_name_len, name);
-
- if (found)
- break;
-
- file_pos += de_len;
- }
-
- if ( file_pos >= dir->dir_len )
- return 0; /* not found */
-
-
- if ( *(name+de_name_len) && (*(name+de_name_len) != '/' ) ) {
- printf("Something wrong happened during searching file %s\n", name);
-
- *res = NULL;
- return 0;
- }
-
- if ( de->flags & 0x02 ) {
- /* it's a directory */
- dir = &CurrentDir;
- dir->dir_lba = *(uint32_t *)de->extent;
- dir->dir_len = *(uint32_t *)de->size;
- dir->dir_clust = (dir->dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
-
- *file_len = dir->dir_len;
- *res = dir;
-
- /* we can close it now */
- close_pvt(file);
-
- /* Mark we got a directory */
- return 1;
- } else {
- /* it's a file */
- file->file_sector = *(uint32_t *)de->extent;
- file->file_bytesleft = *(uint32_t *)de->size;
- file->file_left = (file->file_bytesleft + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
-
- *file_len = file->file_bytesleft;
- *res = file;
-
- /* Mark we got a file */
- return 2;
+ struct cache_struct *cs = NULL;
+
+ while (1) {
+ if (!cs) {
+ if (++i > inode->blocks)
+ return NULL;
+ cs = get_cache_block(this_fs->fs_dev, dir_block++);
+ de = (struct iso_dir_entry *)cs->data;
+ offset = 0;
+ }
+ de = (struct iso_dir_entry *)(cs->data + offset);
+
+ de_len = de->length;
+ if (de_len == 0) { /* move on to the next block */
+ cs = NULL;
+ continue;
+ }
+ offset += de_len;
+
+ /* Make sure we have a full directory entry */
+ if (offset >= BLOCK_SIZE(this_fs)) {
+ int slop = de_len + BLOCK_SIZE(this_fs) - offset;
+
+ memcpy(&tmpde, de, slop);
+ offset &= BLOCK_SIZE(this_fs) - 1;
+ if (offset) {
+ if (++i > inode->blocks)
+ return NULL;
+ cs = get_cache_block(this_fs->fs_dev, dir_block++);
+ memcpy((void *)&tmpde + slop, cs->data, offset);
+ }
+ de = &tmpde;
+ }
+
+ if (de_len < 33) {
+ printf("Corrupted directory entry in sector %u\n",
+ (uint32_t)(dir_block - 1));
+ return NULL;
+ }
+
+ de_name_len = de->name_len;
+ de_name = de->name;
+ /* Handling the special case ".' and '..' here */
+ if((de_name_len == 1) && (*de_name == 0)) {
+ de_name = ".";
+ } else if ((de_name_len == 1) && (*de_name == 1)) {
+ de_name ="..";
+ de_name_len = 2;
+ }
+ if (iso_compare_name(de_name, de_name_len, dname))
+ return de;
}
}
-
-/*
- * open a file
- *
- * searchdir_iso is a special entry point for ISOLINUX only. In addition
- * to the above, searchdir_iso passes a file flag mask in AL. This is
- * useful for searching for directories.
- *
- * well, it's not like the searchidr function in EXT fs or FAT fs; it also
- * can read a diretory.(Just thought of mine, liu)
- *
- */
-static void iso_searchdir(char *filename, struct file *file)
+static inline int get_inode_mode(uint8_t flags)
{
- struct open_file_t *open_file = NULL;
- struct dir_t *dir;
- uint32_t file_len = 0;
- int ret;
- void *res;
+ if (flags & 0x02)
+ return I_DIR;
+ else
+ return I_FILE;
+}
- dir = &CurrentDir;
- if ( *filename == '/' ) {
- dir = &RootDir;
- filename ++;
- }
+static struct inode *iso_get_inode(struct iso_dir_entry *de)
+{
+ struct inode *inode = new_iso_inode();
+
+ if (!inode)
+ return NULL;
+ inode->mode = get_inode_mode(de->flags);
+ inode->size = *(uint32_t *)de->size;
+ *inode->data = *(uint32_t *)de->extent;
+ inode->blocks = (inode->size + BLOCK_SIZE(this_fs) - 1)
+ >> this_fs->block_shift;
+
+ return inode;
+}
- while ( *filename ) {
- ret = do_search_dir(file->fs, dir, filename, &file_len, &res);
- if ( ret == 1 )
- dir = (struct dir_t *)res;
- else if ( ret == 2 )
- break;
- else
- goto err;
- /* find the end */
- while ( *filename && (*filename != '/') )
- filename ++;
+static struct inode *iso_iget_root(void)
+{
+ struct inode *inode = new_iso_inode();
+ struct iso_dir_entry *root = &ISO_SB(this_fs)->root;
+
+ if (!inode)
+ return NULL;
+
+ inode->mode = I_DIR;
+ inode->size = *(uint32_t *)root->size;
+ *inode->data = *(uint32_t *)root->extent;
+ inode->blocks = (inode->size + BLOCK_SIZE(this_fs) - 1)
+ >> this_fs->block_shift;
+
+ return inode;
+}
- /* skip the slash */
- while ( *filename && (*filename == '/') )
- filename++;
- }
+static struct inode *iso_iget(char *dname, struct inode *parent)
+{
+ struct iso_dir_entry *de;
+
+ de = iso_find_entry(dname, parent);
+ if (!de)
+ return NULL;
+
+ return iso_get_inode(de);
+}
- /* well , we need recheck it , becuase it can be a directory */
- if ( ret == 2 ) {
- open_file = (struct open_file_t *)res;
- goto found;
- } else {
- open_file = allocate_file();
- if ( !open_file )
- goto err;
+/* Convert to lower case string */
+static void tolower_str(char *str)
+{
+ while (*str) {
+ if (*str >= 'A' && *str <= 'Z')
+ *str = *str + 0x20;
+ str++;
+ }
+}
- open_file->file_sector = dir->dir_lba;
- open_file->file_bytesleft = dir->dir_len;
- open_file->file_left = (dir->dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
- goto found;
+static struct dirent *iso_readdir(struct file *file)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ struct iso_dir_entry *de, tmpde;
+ struct dirent *dirent;
+ struct cache_struct *cs = NULL;
+ block_t block = *file->inode->data + (file->offset >> fs->block_shift);
+ int offset = file->offset & (BLOCK_SIZE(fs) - 1);
+ int i = 0;
+ int de_len, de_name_len;
+ char *de_name;
+
+ while (1) {
+ if (!cs) {
+ if (++i > inode->blocks)
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, block++);
+ }
+ de = (struct iso_dir_entry *)(cs->data + offset);
+
+ de_len = de->length;
+ if (de_len == 0) { /* move on to the next block */
+ cs = NULL;
+ file->offset = (file->offset + BLOCK_SIZE(fs) - 1)
+ >> fs->block_shift;
+ continue;
+ }
+ offset += de_len;
+
+ /* Make sure we have a full directory entry */
+ if (offset >= BLOCK_SIZE(fs)) {
+ int slop = de_len + BLOCK_SIZE(fs) - offset;
+
+ memcpy(&tmpde, de, slop);
+ offset &= BLOCK_SIZE(fs) - 1;
+ if (offset) {
+ if (++i > inode->blocks)
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, block++);
+ memcpy((void *)&tmpde + slop, cs->data, offset);
+ }
+ de = &tmpde;
+ }
+
+ if (de_len < 33) {
+ printf("Corrupted directory entry in sector %u\n",
+ (uint32_t)(block - 1));
+ return NULL;
+ }
+
+ de_name_len = de->name_len;
+ de_name = de->name;
+ /* Handling the special case ".' and '..' here */
+ if((de_name_len == 1) && (*de_name == 0)) {
+ de_name = ".";
+ } else if ((de_name_len == 1) && (*de_name == 1)) {
+ de_name ="..";
+ de_name_len = 2;
+ }
+
+ break;
}
- err:
- close_pvt(open_file);
- file_len = 0;
- open_file = NULL;
-
- found:
- file->file_len = file_len;
- file->open_file = (void*)open_file;
-
-#if 0
- if (open_file) {
- printf("file bytesleft: %d\n", open_file->file_bytesleft);
- printf("file sector : %d\n", open_file->file_sector);
- printf("file in sector: %d\n", open_file->file_in_sec);
- printf("file offsector: %d\n", open_file->file_in_off);
+
+ if (!(dirent = malloc(sizeof(*dirent)))) {
+ malloc_error("dirent structure in iso_readdir");
+ return NULL;
}
-#endif
+
+ dirent->d_ino = 0; /* Inode number is invalid to ISO fs */
+ dirent->d_off = file->offset;
+ dirent->d_reclen = de_len;
+ dirent->d_type = get_inode_mode(de->flags);
+ iso_convert_name(dirent->d_name, de_name, de_name_len);
+ tolower_str(dirent->d_name);
+
+ file->offset += de_len; /* Update for next reading */
+
+ return dirent;
}
/* Load the config file, return 1 if failed, or 0 */
static int iso_load_config(void)
{
- char *config_name = "isolinux.cfg";
+ const char *config_file[] = {
+ "/boot/isolinux/isolinux.cfg",
+ "/isolinux/isolinux.cfg"
+ };
com32sys_t regs;
+ int i = 0;
+ char *p;
- memset(&regs, 0, sizeof regs);
- strcpy(ConfigName, config_name);
- regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
- call16(core_open, &regs, &regs);
-
- return !!(regs.eflags.l & EFLAGS_ZF);
+ for (; i < 2; i++) {
+ memset(&regs, 0, sizeof regs);
+ strcpy(ConfigName, config_file[i]);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ call16(core_open, &regs, &regs);
+ if (!(regs.eflags.l & EFLAGS_ZF))
+ break;
+ }
+ if (i == 2) {
+ printf("No config file found\n");
+ return 1;
+ }
+
+ strcpy(ConfigName, "isolinux.cfg");
+ strcpy(CurrentDirName, config_file[i]);
+ p = strrchr(CurrentDirName, '/');
+ *p = '\0';
+
+ return 0;
}
static int iso_fs_init(struct fs_info *fs)
{
- char *iso_dir;
- char *boot_dir = "/boot/isolinux";
- char *isolinux_dir = "/isolinux";
- int len;
- int bi_pvd = 16;
- struct file file;
- struct open_file_t *open_file;
- struct disk *disk = fs->fs_dev->disk;
-
- block_shift = ISO_SECTOR_SHIFT - disk->sector_shift;
- cdrom_read_sectors(disk, trackbuf, bi_pvd, 1);
- CurrentDir.dir_lba = RootDir.dir_lba = *(uint32_t *)(trackbuf + 156 + 2);
-
-#ifdef DEBUG
- printf("Root directory at LBA = 0x%x\n", RootDir.dir_lba);
-#endif
-
- CurrentDir.dir_len = RootDir.dir_len = *(uint32_t*)(trackbuf + 156 + 10);
- CurrentDir.dir_clust = RootDir.dir_clust = (RootDir.dir_len + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_SHIFT;
-
- /*
- * Look for an isolinux directory, and if found,
- * make it the current directory instead of the
- * root directory.
- *
- * Also copy the name of the directory to CurrrentDirName
- */
- *(uint16_t *)CurrentDirName = ROOT_DIR_WORD;
-
- iso_dir = boot_dir;
- file.fs = fs;
- iso_searchdir(boot_dir, &file); /* search for /boot/isolinux */
- if ( !file.file_len ) {
- iso_dir = isolinux_dir;
- iso_searchdir(isolinux_dir, &file); /* search for /isolinux */
- if ( !file.file_len ) {
- printf("No isolinux directory found!\n");
- return 0;
- }
+ struct iso_sb_info *sbi;
+
+ this_fs = fs;
+
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi) {
+ malloc_error("iso_sb_info structure");
+ return 1;
}
-
- strcpy(CurrentDirName, iso_dir);
- len = strlen(CurrentDirName);
- CurrentDirName[len] = '/';
- CurrentDirName[len+1] = '\0';
-
- open_file = (struct open_file_t *)file.open_file;
- CurrentDir.dir_len = open_file->file_bytesleft;
- CurrentDir.dir_clust = open_file->file_left;
- CurrentDir.dir_lba = open_file->file_sector;
- close_pvt(open_file);
-
-#ifdef DEBUG
- printf("isolinux directory at LBA = 0x%x\n", CurrentDir.dir_lba);
-#endif
-
- /* we do not use cache for now, so we can just return 0 */
- return 0;
+ fs->fs_info = sbi;
+
+ cdrom_read_blocks(fs->fs_dev->disk, trackbuf, 16, 1);
+ memcpy(&sbi->root, trackbuf + ROOT_DIR_OFFSET, sizeof(sbi->root));
+
+ fs->block_shift = 11;
+ return fs->block_shift;
}
const struct fs_ops iso_fs_ops = {
.fs_name = "iso",
- .fs_flags = 0,
+ .fs_flags = FS_USEMEM | FS_THISIND,
.fs_init = iso_fs_init,
- .searchdir = iso_searchdir,
+ .searchdir = NULL,
.getfssec = iso_getfssec,
.close_file = iso_close_file,
.mangle_name = iso_mangle_name,
.unmangle_name = generic_unmangle_name,
- .load_config = iso_load_config
+ .load_config = iso_load_config,
+ .iget_root = iso_iget_root,
+ .iget_current = NULL,
+ .iget = iso_iget,
+ .readdir = iso_readdir
};
diff --git a/core/fs/iso9660/iso9660_fs.h b/core/fs/iso9660/iso9660_fs.h
index ca123b16..e77ae109 100644
--- a/core/fs/iso9660/iso9660_fs.h
+++ b/core/fs/iso9660/iso9660_fs.h
@@ -3,6 +3,9 @@
#include <stdint.h>
+/* The root dir entry offset in the primary volume descriptor */
+#define ROOT_DIR_OFFSET 156
+
struct iso_dir_entry {
uint8_t length; /* 00 */
uint8_t ext_attr_length; /* 01 */
@@ -14,8 +17,11 @@ struct iso_dir_entry {
uint8_t interleave; /* 1b */
uint8_t volume_sequence_number[4]; /* 1c */
uint8_t name_len; /* 20 */
- //uint8_t name[]; /* 21 */
+ char name[0]; /* 21 */
};
+struct iso_sb_info {
+ struct iso_dir_entry root;
+};
#endif /* iso9660_fs.h */
diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
index 7935f8ba..0787078a 100644
--- a/core/fs/pxe/dhcp_option.c
+++ b/core/fs/pxe/dhcp_option.c
@@ -224,28 +224,26 @@ void parse_dhcp_options(void *option, int size, int filter)
}
/*
+ * parse_dhcp
*
- ;
- ; parse_dhcp
- ;
- ; Parse a DHCP packet. This includes dealing with "overloaded"
- ; option fields (see RFC 2132, section 9.3)
- ;
- ; This should fill in the following global variables, if the
- ; information is present:
- ;
- ; MyIP - client IP address
- ; server_ip - boot server IP address
- ; net_mask - network mask
- ; gate_way - default gateway router IP
- ; boot_file - boot file name
- ; DNSServers - DNS server IPs
- ; LocalDomain - Local domain name
- ; MAC_len, MAC - Client identifier, if MAC_len == 0
- ;
- ; This assumes the DHCP packet is in "trackbuf".
- ;
-*/
+ * Parse a DHCP packet. This includes dealing with "overloaded"
+ * option fields (see RFC 2132, section 9.3)
+ *
+ * This should fill in the following global variables, if the
+ * information is present:
+ *
+ * MyIP - client IP address
+ * server_ip - boot server IP address
+ * net_mask - network mask
+ * gate_way - default gateway router IP
+ * boot_file - boot file name
+ * DNSServers - DNS server IPs
+ * LocalDomain - Local domain name
+ * MAC_len, MAC - Client identifier, if MAC_len == 0
+ *
+ * This assumes the DHCP packet is in "trackbuf".
+ *
+ */
void parse_dhcp(int pkt_len)
{
struct bootp_t *dhcp = (struct bootp_t *)trackbuf;
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index 0e6e2271..1bbb6b0a 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -1571,5 +1571,6 @@ const struct fs_ops pxe_fs_ops = {
.close_file = pxe_close_file,
.mangle_name = pxe_mangle_name,
.unmangle_name = pxe_unmangle_name,
- .load_config = pxe_load_config
+ .load_config = pxe_load_config,
+ .iget_current = NULL
};
diff --git a/core/include/core.h b/core/include/core.h
index dbcbff1c..1a9e1b96 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -23,6 +23,11 @@ extern void (*idle_hook_func)(void);
/* hello.c */
extern void myputs(const char*);
+/* malloc.c */
+extern void *malloc(int);
+extern void free(void *);
+extern void mem_init(void);
+
void __cdecl core_intcall(uint8_t, const com32sys_t *, com32sys_t *);
void __cdecl core_farcall(uint32_t, const com32sys_t *, com32sys_t *);
int __cdecl core_cfarcall(uint32_t, const void *, uint32_t);
diff --git a/core/include/disk.h b/core/include/disk.h
index 91f7a57a..55d24fbc 100644
--- a/core/include/disk.h
+++ b/core/include/disk.h
@@ -6,7 +6,6 @@
#include <stdbool.h>
#define SECTOR_SHIFT 9
-#define SECTOR_SIZE (1 << SECTOR_SHIFT)
typedef uint64_t sector_t;
typedef uint64_t block_t;
diff --git a/core/include/fs.h b/core/include/fs.h
index df103023..f0fe5347 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -5,6 +5,7 @@
#include <stdbool.h>
#include <string.h>
#include <com32.h>
+#include <stdio.h>
#include "core.h"
#include "disk.h"
@@ -20,22 +21,30 @@
#define FILENAME_MAX_LG2 8
#define FILENAME_MAX (1 << FILENAME_MAX_LG2)
+#define BLOCK_SIZE(fs) (1 << fs->block_shift)
+#define SECTOR_SIZE(fs) (1 << fs->sector_shift)
+
struct fs_info {
const struct fs_ops *fs_ops;
struct device *fs_dev;
+ void *fs_info; /* The fs-specific information */
+ int sector_shift;
+ int block_shift;
};
-struct open_file_t; /* Filesystem private structure */
-struct dirent; /* Directory entry structure */
-
-struct file {
- struct open_file_t *open_file; /* Filesystem private data */
- struct fs_info *fs;
- uint32_t file_len;
-};
+extern struct fs_info *this_fs;
+struct dirent; /* Directory entry structure */
+struct file;
enum fs_flags {
- FS_NODEV = 1,
+ FS_NODEV = 1 << 0,
+ FS_USEMEM = 1 << 1, /* If we need a malloc routine, set it */
+
+ /*
+ * Update the this_inode pointer at each part of path searching. This
+ * flag is just used for FAT and ISO fs for now.
+ */
+ FS_THISIND = 1 << 2,
};
struct fs_ops {
@@ -51,11 +60,56 @@ struct fs_ops {
char * (*unmangle_name)(char *, const char *);
int (*load_config)();
+ struct inode * (*iget_root)(void);
+ struct inode * (*iget_current)(void);
+ struct inode * (*iget)(char *, struct inode *);
+ char * (*follow_symlink)(struct inode *, const char *);
+
/* the _dir_ stuff */
- void (*opendir)(com32sys_t *);
struct dirent * (*readdir)(struct file *);
};
+enum inode_mode {I_FILE, I_DIR, I_SYMLINK};
+
+/*
+ * The inode structure, including the detail file information
+ */
+struct inode {
+ int mode; /* FILE , DIR or SYMLINK */
+ uint32_t size;
+ uint32_t ino; /* Inode number */
+ uint32_t atime; /* Access time */
+ uint32_t mtime; /* Modify time */
+ uint32_t ctime; /* Create time */
+ uint32_t dtime; /* Delete time */
+ int blocks; /* How many blocks the file take */
+ uint32_t * data; /* The block address array where the file stored */
+ uint32_t flags;
+ uint32_t file_acl;
+};
+
+extern struct inode *this_inode;
+
+struct open_file_t;
+
+struct file {
+ struct fs_info *fs;
+ union {
+ /* For the new universal-path_lookup */
+ struct {
+ struct inode *inode; /* The file-specific information */
+ uint32_t offset; /* for next read */
+ };
+
+ /* For the old searhdir method */
+ struct {
+ struct open_file_t *open_file;/* The fs-specific open file struct */
+ uint32_t file_len;
+ };
+ };
+};
+
+
enum dev_type {CHS, EDD};
/*
@@ -88,6 +142,21 @@ static inline bool not_whitespace(char c)
return (unsigned char)c > ' ';
}
+static inline void free_inode(struct inode * inode)
+{
+ if (inode) {
+ if (inode->data)
+ free(inode->data);
+ free(inode);
+ }
+}
+
+static inline void malloc_error(char *obj)
+{
+ printf("Out of memory: can't allocate memory for %s\n", obj);
+ kaboom();
+}
+
/*
* functions
*/
diff --git a/core/malloc.c b/core/malloc.c
new file mode 100644
index 00000000..a033ff03
--- /dev/null
+++ b/core/malloc.c
@@ -0,0 +1,216 @@
+/*
+ * A simple temp malloc for Sysliux project from fstk. For now, just used
+ * in fsc branch, which it's would be easy to remove it when we have a
+ * powerful one, as hpa said this would happen when elflink branch do the
+ * work.
+ *
+ * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file
+ * may be redistributed under the terms of the GNU Public License.
+ */
+
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+/* The memory managemant structure */
+struct mem_struct {
+ struct mem_struct *prev;
+ int size;
+ int free;
+};
+
+
+/* First, assume we just need 64K memory */
+static char memory[0x10000];
+
+/* Next free memory address */
+static struct mem_struct *next_start = (struct mem_struct *)memory;
+static uint32_t mem_end = (uint32_t)(memory + 0x10000);
+
+
+static inline struct mem_struct *get_next(struct mem_struct *mm)
+{
+ uint32_t next = (uint32_t)mm + mm->size;
+
+ if (next >= mem_end)
+ return NULL;
+ else
+ return (struct mem_struct *)next;
+}
+
+/*
+ * Here are the _merge_ functions, that merges a adjacent memory region,
+ * from front, or from back, or even merges both. It returns the headest
+ * region mem_struct.
+ *
+ */
+
+static struct mem_struct * merge_front(struct mem_struct *mm,
+ struct mem_struct *prev)
+{
+ struct mem_struct *next = get_next(mm);
+
+ prev->size += mm->size;
+ if (next)
+ next->prev = prev;
+ return prev;
+}
+
+static struct mem_struct * merge_back(struct mem_struct *mm,
+ struct mem_struct *next)
+{
+ mm->free = 1; /* Mark it free first */
+ mm->size += next->size;
+
+ next = get_next(next);
+ if (next)
+ next->prev = mm;
+ return mm;
+}
+
+static struct mem_struct * merge_both(struct mem_struct *mm,
+ struct mem_struct *prev,
+ struct mem_struct *next)
+{
+ prev->size += mm->size + next->size;
+
+ next = get_next(next);
+ if (next)
+ next->prev = prev;
+ return prev;
+}
+
+static inline struct mem_struct * try_merge_front(struct mem_struct *mm)
+{
+ mm->free = 1;
+ if (mm->prev->free)
+ mm = merge_front(mm, mm->prev);
+ return mm;
+}
+
+static inline struct mem_struct * try_merge_back(struct mem_struct *mm)
+{
+ struct mem_struct *next = get_next(mm);
+
+ mm->free = 1;
+ if (next->free)
+ merge_back(mm, next);
+ return mm;
+}
+
+/*
+ * Here's the main function, malloc, which allocates a memory rigon
+ * of size _size_. Returns NULL if failed, or the address newly allocated.
+ *
+ */
+void *malloc(int size)
+{
+ struct mem_struct *next = next_start;
+ struct mem_struct *good = next, *prev;
+ int size_needed = (size + sizeof(struct mem_struct) + 3) & ~3;
+
+ while(next) {
+ if (next->free && next->size >= size_needed) {
+ good = next;
+ break;
+ }
+ next = get_next(next);
+ }
+ if (good->size < size_needed) {
+ printf("Out of memory, maybe we need append it\n");
+ return NULL;
+ } else if (good->size == size_needed) {
+ /*
+ * We just found a right memory that with the exact
+ * size we want. So we just Mark it _not_free_ here,
+ * and move on the _next_start_ pointer, even though
+ * the next may not be a right next start.
+ */
+ good->free = 0;
+ next_start = get_next(good);
+ goto out;
+ } else
+ size = good->size; /* save the total size */
+
+ /*
+ * Note: allocate a new memory region will not change
+ * it's prev memory, so we don't need change it here.
+ */
+ good->free = 0; /* Mark it not free any more */
+ good->size = size_needed;
+
+ next = get_next(good);
+ if (next) {
+ next->size = size - size_needed;
+ /* check if it can contain 1 byte allocation at least */
+ if (next->size <= (int)sizeof(struct mem_struct)) {
+ good->size = size; /* restore the original size */
+ next_start = get_next(good);
+ goto out;
+ }
+
+ next->prev = good;
+ next->free = 1;
+ next_start = next; /* Update next_start */
+
+ prev = next;
+ next = get_next(next);
+ if (next)
+ next->prev = prev;
+ } else
+ next_start = (struct mem_struct *)memory;
+out:
+ return (void *)((uint32_t)good + sizeof(struct mem_struct));
+}
+
+void free(void *ptr)
+{
+ struct mem_struct *mm = ptr - sizeof(*mm);
+ struct mem_struct *prev = mm->prev;
+ struct mem_struct *next = get_next(mm);
+
+ if (!prev)
+ mm = try_merge_back(mm);
+ else if (!next)
+ mm = try_merge_front(mm);
+ else if (prev->free && !next->free)
+ merge_front(mm, prev);
+ else if (!prev->free && next->free)
+ merge_back(mm, next);
+ else if (prev->free && next->free)
+ merge_both(mm, prev, next);
+ else
+ mm->free = 1;
+
+ if (mm < next_start)
+ next_start = mm;
+}
+
+/*
+ * The debug function
+ */
+void check_mem(void)
+{
+ struct mem_struct *next = (struct mem_struct *)memory;
+
+ printf("____________\n");
+ while (next) {
+ printf("%-6d %s\n", next->size, next->free ? "Free" : "Notf");
+ next = get_next(next);
+ }
+ printf("\n");
+}
+
+
+void mem_init(void)
+{
+
+ struct mem_struct *first = (struct mem_struct *)memory;
+
+ first->prev = NULL;
+ first->size = 0x10000;
+ first->free = 1;
+
+ next_start = first;
+}