aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu Aleaxander <Aleaxander@gmail.com>2009-05-16 15:07:00 +0800
committerLiu Aleaxander <Aleaxander@gmail.com>2009-05-16 15:07:00 +0800
commit487239a50776f619e41ce5a2c9f2f9db6038b8f4 (patch)
treedd80e5227ba97205be86b8b4829b192ae2d3e243
parentfdae58f8e25461c8e44c15afd6172ca5428ca8d2 (diff)
downloaddevel-487239a50776f619e41ce5a2c9f2f9db6038b8f4.tar.gz
devel-487239a50776f619e41ce5a2c9f2f9db6038b8f4.tar.xz
devel-487239a50776f619e41ce5a2c9f2f9db6038b8f4.zip
Add fat file system stuffle
-rw-r--r--fat_fs.h111
-rw-r--r--ldlinux.c543
2 files changed, 654 insertions, 0 deletions
diff --git a/fat_fs.h b/fat_fs.h
new file mode 100644
index 0000000..a15bd82
--- /dev/null
+++ b/fat_fs.h
@@ -0,0 +1,111 @@
+#ifndef _FAT_FS_H
+#define _FAT_FS_H
+
+#include "types.h"
+
+
+#define FAT_DIR_ENTRY_SIZE 32
+
+#define FAT_ATTR_READ_ONLY 0x01
+#define FAT_ATTR_HIDDEN 0x02
+#define FAT_ATTR_SYSTEM 0x04
+#define FAT_ATTR_VOLUME_ID 0x08
+#define FAT_ATTR_DIRECTORY 0x10
+#define FAT_ATTR_ARCHIVE 0x20
+
+#define FAT_MAXFILE 256
+
+#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_VOLUME_ID)
+
+#define FAT_ATTR_VALID (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_DIRECTORY \
+ | FAT_ATTR_ARCHIVE)
+
+/*
+ * The fat file system structures
+ */
+
+struct fat_bpb {
+ __u8 jmp_boot[3];
+ __u8 oem_name[8];
+ __u16 sector_size;
+ __u8 bxSecPerClust;
+ __u16 bxResSectors;
+ __u8 bxFATs;
+ __u16 bxRootDirEnts;
+ __u16 bxSectors;
+ __u8 media;
+ __u16 bxFATsecs;
+ __u16 sectors_per_track;
+ __u16 num_heads;
+ __u32 num_hidden_sectors;
+ __u32 bsHugeSectors;
+
+ union {
+ struct {
+ __u8 num_ph_drive;
+ __u8 reserved;
+ __u8 boot_sig;
+ __u32 num_serial;
+ __u8 label[11];
+ __u8 fstype[8];
+ } __attribute__ ((packed)) fat12_16;
+
+ struct {
+ __u32 bxFATsecs_32;
+ __u16 extended_flags;
+ __u16 fs_version;
+ __u32 root_cluster;
+ __u16 fs_info;
+ __u16 backup_boot_sector;
+ __u8 reserved[12];
+ __u8 num_ph_drive;
+ __u8 reserved1;
+ __u8 boot_sig;
+ __u32 num_serial;
+ __u8 label[11];
+ __u8 fstype[8];
+ } __attribute__ ((packed)) fat32;
+
+ } __attribute__ ((packed)) u;
+
+} __attribute__ ((packed));
+
+
+
+struct fat_dir_entry {
+ __u8 name[11];
+ __u8 attr;
+ __u8 nt_reserved;
+ __u8 c_time_tenth;
+ __u16 c_time;
+ __u16 c_date;
+ __u16 a_date;
+ __u16 first_cluster_high;
+ __u16 w_time;
+ __u16 w_date;
+ __u16 first_cluster_low;
+ __u32 file_size;
+} __attribute__ ((packed));
+
+
+
+struct fat_long_name_entry {
+ __u8 id;
+ __u16 name1[5];
+ __u8 attr;
+ __u8 reserved;
+ __u8 checksum;
+ __u16 name2[6];
+ __u16 first_cluster;
+ __u16 name3[2];
+} __attribute__ ((packed));
+
+
+
+#endif /* fat_fs.h */
diff --git a/ldlinux.c b/ldlinux.c
new file mode 100644
index 0000000..73f3ba2
--- /dev/null
+++ b/ldlinux.c
@@ -0,0 +1,543 @@
+#include "fat_fs.h"
+#include "cache.h"
+#include "disklab.h"
+
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+
+
+/* some generic defines */
+#define FILENAME_MAX_LG2 6
+#define FILENAME_MAX_ ( 1 << FILENAME_MAX_LG2 )
+#define NULLFILE 0
+#define NULLOFFSET 0
+#define retry_count 16
+#define LDLINUX_MAGIC 0x3eb202fe
+
+#define MAX_OPEN_LG2 6
+#define MAX_OPEN ( 1 << MAX_OPEN_LG2 )
+
+#define SECTOR_SHIFT 9
+#define SECTOR_SIZE ( 1 << SECTOR_SHIFT )
+
+#define DIRENT_SHIFT 5
+#define DIRENT_SIZE ( 1 << DIRENT_SHIFT )
+
+#define ROOT_DIR_WORD 0x002f
+
+
+/* generic information about FAT fs */
+
+__u32 FAT; /* Location of (first) FAT */
+__u32 RootDirArea; /* Location of root directory area */
+__u32 RootDir; /* Location of root directory proper */
+__u32 DataArea; /* Location of data area */
+__u32 TotalSectors; /* Total number of sectors */
+__u32 ClustSize; /* Bytes/cluster */
+__u32 ClustMask; /* Sector/cluster - 1 */
+__u8 CopySuper; /* Distinguish .bs versus .bss */
+__u8 DriveNumber; /* BIOS drive number */
+__u8 ClustShift; /* Shift count for sectors/cluster */
+__u8 ClustByteShift; /* Shift count for bytes/cluster */
+
+/* for SYSLINUX, the block size equal to the sector size */
+__u32 blk_size = 1 << SECTOR_SHIFT;
+
+
+/* file structure. This holds the information for each currently open file */
+struct open_file_t {
+ __u32 file_sector; /* sector pointer ( 0 = structure free ) */
+ __u32 file_bytesleft; /* number of bytes left */
+ __u32 file_left; /* number of sectors left */
+ __u32 pad; /* padding */
+};
+
+struct open_file_t Files[MAX_OPEN];
+
+#define trackbufsize 8192
+char trackbuf[trackbufsize];
+
+
+/* the fat bpb data */
+struct fat_bpb fat;
+
+
+
+
+/**
+ * allocate_file:
+ *
+ * Allocate a file structure
+ *
+ * @return: if successful return the file pointer, or return NULL
+ *
+ */
+struct open_file_t *allocate_file()
+{
+ struct open_file_t *file;
+ int i = 0;
+
+ file = Files;
+
+ for (; i < MAX_OPEN; i ++ ) {
+ if ( file->file_sector == 0 ) /* found it */
+ return file;
+ file ++;
+ }
+
+ return NULL; /* not found */
+}
+
+
+/**
+ * alloc_fill_dir:
+ *
+ * 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.
+ *
+ */
+struct open_file_t* alloc_fill_dir(__u32 sector)
+{
+ struct open_file_t *file;
+
+ file = allocat_file();
+ if ( !file )
+ return NULL;
+
+ file->file_sector = sector; /* current sector */
+ file->file_bytesleft = 0; /* current offset */
+ file->file_left = sector; /* beginning sector */
+
+ return file;
+}
+
+
+/* Deallocates a file structure */
+void close_file(struct open_file_t *file)
+{
+ if ( !file )
+ file->file_sector = 0;
+}
+
+
+
+/* Deallocates a directory structure */
+void close_dir(xxx* yy)
+{
+ if ( !yy )
+ *yy = 0;
+}
+
+
+
+
+/**
+ * getfssec_edx:
+ *
+ * get multiple sectors from a file
+ *
+ * This routine makes sure the subransfers do not cross a 64K boundary
+ * and will correct the situation if it does, UNLESS *sectos* cross
+ * 64K boundaries.
+ *
+ * @param: buf
+ * @param: curr_sector
+ * @param: sectors
+ *
+ */
+void getfssec_edx(char *buf, __u32 curr_sector, __u32 sectors)
+{
+
+}
+
+
+
+
+
+
+/**
+ * getfssec:
+ *
+ * get multiple sectors from a file
+ *
+ *
+ * @param: buf
+ * @param: file
+ * @param: sectors
+ *
+ * @return: number of bytes read
+ *
+ */
+void getfssec(char *buf, struct open_file_t *file, __u32 sectors)
+{
+ __u32 bytes_read;
+
+ if ( sectors > file_file_left )
+ sectors = file->file_left;
+ bytes_read = sectors << SECTOR_SHIFT;
+
+ file->file_left -= sectors;
+ edx = file_file_sector;
+ getfssec_edx(buf, edx, sectors);
+
+ if ( bytes_read >= file->file_bytesleft ) {
+ bytes_read = file->file_bytesleft;
+ file->file_bytesleft = 0;
+
+ close_file(file);
+ } else
+ file->file_bytesleft -= bytes_read;
+
+ return bytes_read;
+}
+
+
+
+
+
+
+
+
+
+
+/**
+ * mangle_dos_name:
+ *
+ * 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!
+ *
+ * @param: filename
+ * @param: MangleBuf
+ *
+ */
+void mangle_dos_name(char *MangleBuf, char* filename)
+{
+
+ char *di = MangleBuf;
+ char *NameStart = str;
+ char al, ah;
+ unsigned short ax;
+
+ int cx = 11; /* # of bytes to write */
+ int NameLen;
+ loop:
+ do {
+ al = *str ++;
+ if ( al <= ' ' || al == '/')
+ goto end;
+ if ( al == '.' )
+ goto is_period;
+
+ if ( al >= 'a' && al <= 'z')
+ al -= 32;
+
+
+ ah = cx; /* if the first byte (only!)...*/
+ ax = (ah << 8) | al;
+ printf("---ax = 0x%x---\n", ax);
+ if ( ax == 0x0be5 )
+ al = 0x05; /* change it to 05 hex */
+ *di ++ = al;
+
+ }while( --cx ); /* don't continue if too long */
+
+ /* find the end for the benefit of longname search */
+ do {
+ al = *str ++;
+ if ( al <= ' ' )
+ break;
+ }while( al != '/' );
+ end:
+
+ while( cx -- )
+ *di ++ = ' ';
+ *di = '\0';
+ return ;
+
+ is_period:
+ al = ' ';
+ do {
+ if (cx <= 3) /* if <= 3 characters left */
+ goto loop; /* just ignore it */
+ *di ++ = al;
+ }while ( --cx );
+ *di = '\0';
+}
+
+
+
+
+/**
+ * search_dos_dir:
+ *
+ * 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
+ * @out: dh, clobbered.
+ *
+ */
+struct open_file_t* search_dos_dir(char *MangleBuf, __u32 dir_sector)
+{
+ struct open_file_t* file;
+ struct cache_struct* cs;
+ struct fat_dir_entry *dir;
+ struct fat_long_name_entry *long_dir;
+
+ __u32 slots;
+
+ file = allocate_file();
+ if ( !file )
+ goto alloc_failure;
+
+ slots = (NameLen + 12) / 13;
+ slots != 0x40;
+
+ VFATInit = slots;
+ VFATNext = slots;
+
+ scansector:
+ cs = get_cache_block(dir_sector);
+ dir = (struct fat_dir_entry *)cs->data;
+ entries = SECTOR_SIZE / 32;
+
+ scanentry:
+ if ( *(char *)dir == 0 )
+ goto failure;
+ if ( dir->attr != 0x0f )
+ goto short_entry;
+
+ /* Else it's a long name entry */
+ long_dir = (struct fat_long_name_entry *)dir;
+ id = long_dir->id;
+ if ( id !=VFATNext )
+ goto not_us;
+
+ if ( id & 0x40 )
+ VFATCsum = long_dir->checksum;/*get the initial checksum value*/
+ else {
+ if ( long_dir->checksum != VFATCsum )
+ goto not_us;
+ }
+
+ done_csum:
+ id &= 0x3f;
+ if ( !id )
+ goto not_us;
+
+ VFATNext = --id;
+ index = id * 13;
+ if ( index >= NameLen )
+ goto not_us;
+
+ di = NameStart;
+ cx = 13;
+ vfat_cmp:
+ do {
+ if ( index >= NameLen )
+ goto vfat_tail;
+
+ }while(--cx);
+
+
+
+
+
+
+
+
+}
+
+
+
+
+
+/**
+ * searchdir:
+ *
+ * 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.
+ *
+ */
+struct open_file_t* searchdir(char *filename, __u32 *file_len)
+{
+ __u32 dir_sector, prev_dir;
+ char *p;
+
+ struct open_file_t *file;
+
+ dir_sector = CurrentDir;
+ if ( *filename == '/' ) {
+ dir_sector = RootDir;
+ filename ++;
+ }
+
+ pathwalk:
+ p = filename;
+
+ while ( (*p > ' ') && (*p != '/') )
+ p ++;
+
+ //xchg(filename, p);
+ if (filename == p)
+ goto founddir;
+
+ prev_dir = dir_sector;
+
+ mangle_dos_name(filename);
+ file = search_dos_dir(filename);
+ if ( !file )
+ goto notfound;
+
+ if ( *p == '/' )
+ goto isdir;
+ isfile:
+ if ( (attr & 0x18) || (*file_len == 0) )
+ goto badfile;
+
+ file->file_bytesleft = *file_len; /**/
+ file->file_left = ( *file_len + SECTOR_SIZE -1 ) >> SECTOR_SHIFT;
+
+ return file;
+
+ isdir:
+ if ( attr & 0x10 ) /* subdirectory */
+ goto badfile;
+
+ dir_sector = file->file_sector;
+ close(file);
+
+ goto pathwalk;
+
+ founddir:
+ ret;
+ badfile:
+ *file_len = 0;
+ notfound:
+ *file_len = 0;
+ ret;
+}
+
+
+
+
+/**
+ * readdir:
+ *
+ * read one file from a directory
+ *
+ * returns the file's name in the filename string buffer
+ *
+ * @param: filename
+ * @param: file
+ *
+ */
+void readdir(struct open_file_t* file, char* filename)
+{
+
+
+}
+
+
+/**
+ * getfatsector:
+ *
+ * check for a particular sector in the FAT cache.
+ *
+ */
+struct cache_struct *getfatsector(__u32 sector)
+{
+ return get_cache_block(FAT + sector);
+}
+
+
+/**
+ * nextsector:
+ *
+ * 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.
+ *
+ */
+void nextsector(__u32 sector)
+{
+
+
+
+
+
+
+
+}
+
+
+
+
+/**
+ * nextcluster:
+ *
+ * Advance a cluster pointer in clust_num to the next cluster
+ * pointer at in the FAT tables. CF = 0 on return if end of file.
+ *
+ * @param: clust_num;
+ *
+ */
+void nextcluster(__u32 clust_num)
+{
+
+
+ nextcluster_fat12:
+
+ nextcluster_fat16:
+
+ nextcluster_fat28:
+
+}
+
+
+
+
+
+
+/* init. the fs meta data */
+void init_fs()
+{
+ int sectors_per_fat;
+
+ /* get the fat bpb information */
+ getlinsec(&fat, 0, 1);
+
+ TotalSectors = fat.bxSectors ? : fat.bsHugeSectors;
+ FAT = fat.bxResSectors;
+
+ sectors_per_fat = fat.bxFATsecs ? : fat.bxFATsecs_32;
+ RootDir = RootDirArea = FAT + sectors_per_fat * fat.bxFATs;
+ RootDirSize = (fat.bxRootDirEnts+SECTOR_SIZE/32-1) >> (SECTOR_SHFIT-5);
+ DataArea = RootDirArea + RootDirSize;
+
+ bsr(ClustShift, bxSecPerClust);
+ ClustByteShift = ClustShift + SECTOR_SHIFT;
+ ClustMask = fat.bxSecPerClust - 1;
+ ClustSize = fat.bxSecPerClust << SECTOR_SIZE;
+
+}
+